阅读浏览器工作原理(四)

281 阅读4分钟

这是我参与更文挑战的第8天,活动详情查看: 更文挑战

阅读浏览器工作原理(四)

布局

布局是递归过程,从根呈现器(对应html元素,尺寸为浏览器可见区域,window.innerWidth/Height)开始递归遍历层次,并调用子代的layout方法进行布局,这时会为每个需要计算的呈现器计算几何信息。

htm采用基于流的布局模型,所以大多数情况下只需要从上往下,从左往右的顺序一次遍历即可。但是也有例外,html表格的计算就需要不止一次的遍历。

全局布局和增量布局

  1. 全局布局

    触发了整个呈现树的布局,往往是同步触发的,如:

    1. 全局样式更改:如字体大小更改
    2. 屏幕大小调整、页面发生滚动。
  2. 增量布局

    浏览器采用dirty位系统,对发生了更改的呈现进行标记。如果有子元素发生更改则标记为children are dirty,如果是元素本身发生更改则标记为dirty。

    增量布局可能是异步触发的,例如经过网络请求后有额外的内容添加到dom树中,导致生成新的呈现器。firefox会将reflow命令保存到队列,再由调度程序批量执行,用合并命令的方式减少操作。webkit会采用定时器的方式,遍历呈现器并对dirty呈现器布局。

    也可能是同步触发的,例如脚本请求样式信息(.offsetHeight),浏览器为了获取最新的值会应用所有的更改,强制刷新渲染队列。

浏览器的优化措施

  1. 如果是调整了浏览器视口的大小或者是呈现器的位置触发重排,就可以从缓存中获取呈现器大小,不用重新计算。
  2. 如果只有一个子树进行了修改就不用触发根节点的布局。例如在文本中插入文字。

布局流程

  1. 父呈现器确认自身宽度

    如果是以下html代码:

    <div style="width: 30%"></div>
    
    1. 计算父容器宽度availableWidth:clientWidth()-paddingLeft()-paddingRight(),最后取max(availableWidth, 0)
    2. 计算元素宽度:availableWidth*30%,再加上边距和边框。
    3. 判断是否有设置max/min-width,取min(元素宽度,max-width)或max(元素宽度,min-width)。
  2. 处理子呈现器

    1. 设置其坐标
    2. 如果子呈现器是dirty的,或者是全局布局,就调用其layout。
  3. 父呈现器根据子呈现器的新高度+边距来设置自身高度

  4. 将dirty位设置为false

换行

如果呈现器布局过程中需要换行,就会停止布局并告知父呈现器需要换行。父呈现器会再创建一个呈现器,并调用其layout进行布局。

绘制

操作系统遍历呈现树并且调用呈现器的paint方法,由用户界面后端将呈现器内容显示在屏幕上。

增量绘制

呈现器发生更改后,将对应的矩形区域设置为无效,操作系统就会认为是dirty区域,并且生成paint事件。操作系统还会把多个区域合并成一个。

在chrome中,呈现器分布在每个标签页的主线程上,而不是浏览器的主线程。他会侦听改变呈现器的事件,然后通知根呈现器,根呈现器遍历找到那个需要更新的呈现器,再由那个呈现器重新绘制自己和子呈现器。

绘制顺序

绘制顺序其实就是堆叠上下文顺序,也就是html内元素发生层叠的时候,元素在用户方向上的顺序。据说有css2规范定义的有点老了,这里先引用张鑫旭大佬的图,后面再开一篇文章详细讲吧:

浏览器对重绘的优化

  1. firefox显示列表

    遍历整个呈现树,为每个矩形设置显示列表,其中按照呈现器的背景、边框等绘制顺序,包含相关的呈现器(背景:xxx呈现器,xxx呈现器这样的吗?)。重新绘制的时候只需要再遍历一次呈现树整理一遍就好了。

  2. webkit矩形存储

    重新绘制前会把原来的矩形存储为位图,只绘制新矩形的不同部分。

重排重绘的触发

第一次渲染的时候必然会触发重排和重绘 剩下的触发重排和重绘的大概情况有:

  • 重排

    1. 改变窗口大小
    2. 改变文字大小
    3. 增加或移除样式表
    4. 内容的改变 例如输入框输入文字
    5. 激活伪类 如:hover
    6. 操作class属性
    7. 脚本操作DOM增删改查
    8. 计算offsetWidth和offsetHeight
    9. 设置style属性
  • 重绘

    1. 只是改变某个元素的背景色
    2. 文字颜色
    3. 边框颜色
    4. 主要就是不影响它周围或内部布局的属性

www.phpied.com/rendering-r…

www.zhangxinxu.com/wordpress/2…

www.zhangxinxu.com/wordpress/2…