在上一步里,浏览器根据 render 树提供的信息对元素进行排版定位它们在页面上的位置,到了最后一步,根据元素样式信息在内存中渲染它的图形,并且把它绘制到对应的位置。
渲染
在前端范畴的渲染,指的是把模型变成位图的过程。位图就是建立在内存里的一张二维表格,把图片里包含的每个像素对应的内容也就是颜色保存进去。做内存占用优化的时候要重点考虑减少位图信息的存储,因为位图信息是DOM树占据浏览器内存最多的信息。
渲染总体来说可以分成: 图 形 \color{#db5a6b}{图形} 图形和 文 字 \color{#db5a6b}{文字} 文字
图形
需要绘制的图形属性有:SVG元素、背景、边框、阴影等,这一部分会由操作系统的底层库提供支持,MAC 有 METAL、WIndows 有 GDI、Android 有 Skia,浏览器会有一层兼容层来处理掉操作系统的差异。
文字
文字也需要底层库来支持,各个操作系统都会有独立的字体库,字体库能根据字符的码点抽取出字体形状。
文字的字形分为 像 素 字 形 \color{#db5a6b}{像素字形} 像素字形、 矢 量 字 形 \color{#db5a6b}{矢量字形} 矢量字形,字体库通常会在 6~8px 等小尺寸提供像素字体,比较大的提供矢量字体,矢量字体需要经历多一次渲染才能渲染到元素的位图上。
在普通情况下,经过渲染生成的位图尺寸和排版时候元素占的尺寸相同,但是有很多 css 属性如阴影等会影响位图的大小,浏览器为了优化会把阴影作为一个独立的盒来处理。
合成
浏览器在渲染的过程不会直接将元素绘制到位图上,渲染过程很复杂,元素之间会互相影响,不直接将元素绘制在位图上能够减少重新渲染。
看一个小例子:
<div class="a">
<div class="b">...</div>
<div class="c" style="transform:translate(0,0)"></div>
</div>
浏览器在合成的时候会把 a、b 两个 div 合成到位图上,而会为 c 单独创建一个合成后的位图,也会被有的人称为合成层,因为聪明的浏览器猜到后续可能会对 c 进行移动操作例如:
document. getElementsByClassName('c').style.transform = "translate(50px, 0)";
所以浏览器会‘猜测’可能变化的元素,把它们排除到合成之外,从而减少绘制次数,这收益相当的高。
浏览器通常根据元素的 position 、transform等属性来‘猜测’这些元素可能会发生变化,从而制定优秀的合成策略。当然浏览器猜测的准确率有限,所以 css 标准还规定了 w i l l − c h a n g e \color{#db5a6b}{will-change} will−change 属性,可以在写代码的时候暗示浏览器这个元素位置或形状将会变化,合理的运用会有挺不错的收益。
绘制
绘制是把“位图最终绘制到屏幕上,变成肉眼可见的图像”的过程,不过,一般来说,浏览器并不需要用代码来处理这个过程,浏览器只需要把最终要显示的位图交给操作系统即可,最终操作系统会把绘制出来的图像存在
显
存
\color{#db5a6b}{显存}
显存中。
绘制的过程也需要遵守响应的规则,会遵循层叠上下文依层绘制到屏幕上。
其实绘制发生的频率远远高于我们的想象,浏览器会监听我们的鼠标,鼠标划过浏览器显示的区域,为了除去鼠标的残影都会造成 重 新 绘 制 \color{#db5a6b}{重新绘制} 重新绘制。
##限制绘制面积
浏览会怎么才能最大程度地限制绘制面积呢?这时候要引入“
脏
矩
形
\color{#db5a6b}{脏矩形}
脏矩形”算法,“脏矩形”算法把屏幕平均分成若干份矩形区域,当元素移动或者其他导致重绘的场景发生,只需重绘涉及到的矩形区域就够了,这有效地减少绘制的消耗。
以上就是浏览器工作的职能,对浏览器感兴趣的同学还可以继续了解一下浏览器的内核更深入地了解它们的能力。
END…我是个有底线的家伙…END