山海科技发展网

08月09日科技常识:从浏览器渲染过程看重绘回流

导读 摘要 今天小编跟大家讲解下有关从浏览器渲染过程看重绘回流 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关从浏览器渲染过...
摘要 今天小编跟大家讲解下有关从浏览器渲染过程看重绘回流 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关从浏览器渲染过程看重

今天小编跟大家讲解下有关从浏览器渲染过程看重绘回流 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关从浏览器渲染过程看重绘回流 的相关资料,希望小伙伴们看了有所帮助。

渲染过程

浏览器渲染过程如下:

解析 html 生成 DOM 树 解析 css 生成 cssOM 树。将 DOM 树和 cssOM 树结合 生成渲染树(Render Tree)。Layout(回流): 根据生成的渲染树 进行回流(Layout) 得到节点的几何信息(位置 大小)。Painting(重绘): 根据渲染树以及回流得到的几何信息 得到节点的绝对像素。Display: 将像素渲染到屏幕上。

阻塞问题:

构建 cssOM 会阻塞浏览器渲染 但不会阻塞解析 html 构建 DOM树。

JavaScript 会阻塞 DOM 树构建。

当 html 解析器遇到一个 script 标签时 它会暂停构建 DOM 将控制权移交给 JavaScript 引擎;等 JavaScript 引擎运行完毕 浏览器会从中断的地方恢复 DOM 构建。

JavaScript 可以查询和修改 DOM 与 cssOM 会导致竞态问题。

浏览器尚未完成 cssOM 的下载和构建 而我们却想在此时运行 JavaScript 会怎样 答案很简单 对性能不利:浏览器将延迟执行 JavaScript 和 DOM 构建 直至其完成 cssOM 的下载和构建。

异步脚本

携带defer属性的脚本 顺序执行 会在DOMContentLoaded事件触发之前执行。

标准里defer是顺序执行 但因为浏览器可能并未按照标准实现 所以现实情况不一定是顺序执行。

携带async属性的脚本 乱序执行 会在loaded事件触发之前执行。

像素管道(pixel pipeline)

浏览器 60 帧刷新率中的每一帧 像素至屏幕管道中的关键点可以分为 5 个步骤。

JavaScript: JavaScript 修改 DOM 和 css。比如用 JavaScript 实现动画。样式计算:根据匹配选择器(例如.headline或.nav > .nav__item)计算出元素的 css 规则并计算每个元素的最终样式。布局(回流):浏览器开始计算元素要占据的空间大小及其在屏幕的位置。网页的布局模式意味着一个元素可能影响其他元素 例如<body>元素的宽度一般会影响其子元素的宽度以及树中各处的节点。绘制(重绘):绘制是填充像素的过程。它涉及绘出文本、颜色、图像、边框和阴影 基本上包括元素的每个可视部分。绘制一般是在多个表面(通常称为层)上完成的。合成:由于页面的各部分可能被绘制到多层 由此它们需要按正确顺序绘制到屏幕上 以便正确渲染页面。对于与另一元素重叠的元素来说 这点特别重要 因为一个错误可能使一个元素错误地出现在另一个元素的上层。

跳过 Layout 和 Paint

更改一个既不要布局也不要绘制的属性 则浏览器将跳过 Layout 和 Paint 只执行 Composite。

跳过 Layout

如果只修改 paint only 属性(例如背景图片、文字颜色或阴影等) 即不会影响页面布局的属性 浏览器会跳过 Layout 过程 但仍将执行 Paint。

这个过程就是浏览器重绘。

无跳过

如果修改元素的 layout 属性 也就是改变了元素的几何属性(例如宽度、高度、左侧或顶部位置等) 浏览器会检查所有其他元素 然后自动重排页面。任何受影响的部分都需要重新绘制 而且最终绘制的元素需会进行合成。

这个过程就是触发回流和重绘。

通过上面的描述可以知道 触发重绘不一定会触发回流 但触发回流一定会触发重绘。

浏览器优化

浏览器为了避免在一帧的时间里频繁的触发回流和重绘过程 会将多次回流、重绘汇总成一次进行处理。一般是将回流、重绘操作推入一个队列中 直到队列达到阈值或者需要执行时 才会清空队列。

强制回流

执行获取布局信息的操作 为了获取正确的数据 浏览器会清空队列 触发回流重绘。

读取以下属性或者使用以下方法会导致强制回流:

offsetTop、offsetLeft、offsetWidth、offsetHeightscrollTop、scrollLeft、scrollWidth、scrollHeightclientTop、clientLeft、clientWidth、clientHeightgetComputedStyle()getBoundingClientRect()...减少回流重绘

避免强制回流

对于频繁读取布局信息的操作 可以使用requestAnimationFrame() 将操作汇集起来并延迟入队 因为requestAnimationFrame()是在每一帧重绘前执行的。

具体查看MDN_requestAnimationFrame

或者将值缓存起来也是可以的。

// 频繁读取布局信息会导致强制回流for (let i = 0; i < arr.length; i++) { arr[i].style.padding = el.style.clientWidth + '5px'; // do something} // 缓存let width = el.style.clientWidth;for (let i = 0; i < arr.length; i++) { arr[i].style.padding = width + '5px'; // do something}

脱离文档流

对于会频繁修改属性的元素 可以使其脱离文档流 这样可以最小化回流和重绘。因为脱离了文档流 修改不会影响文档流整体。

设置 display 为 none设置 position 为 absolute、fixed...

GPU 加速绘制 提升为合成层

所有的元素会在Composite进行渲染层合并 即形成层叠上下文的元素会渲染在不同的渲染层中。

但一个渲染层满足以下条件会被提升为合成层 由硬件加速绘制:

3D transform: translate3d、translateZvideo、canvas、iframe 等元素will-change...

对于动画可以使用 transform 和 opacity 属性 会跳过上面五个步骤中的Layout、Paint 不触发回流重绘 但动画的其它属性 比如 background-color 这些 还是会引起回流重绘。

来源:爱蒂网