CSS属性的渲染步骤及应用渲染方法

浏览器因内核不同对渲染的实现会略有差别,这儿以chrome(74)为例。

渲染步骤

图片[1]-CSS属性的渲染步骤及应用渲染方法-唐朝资源网

渲染的几个关键步骤

recalculatestyle(style):结合DOM和CSSOM,确定各元素应用的CSS规则layout:重新估算各元素位置来布局页面,俗称reflowupdatelayertree(layer):更新渲染树paint:勾画各个视口compositelayers(composite):把各个视口合成为完整页面

渲染过程中,layout可能被跳过,例如对式样的更改不影响layout时,则只需repaint而不需reflow。可以利用CSSTriggers查看什么CSS属性会影响layout。paint也可能被跳过,例如只需重画合成层的内容时。

渲染时机

当DOM或则CSSOM被更改,浏览器并不是立即将改变渲染到屏幕上,而是把renderflag标记为true。在下一个渲染时机假如判定此flag为true,就执行完整渲染过程,再重置renderflag。

渲染时机通常是在上次屏幕刷新前。两次刷新间隔的时间为1帧,1帧的最小值通常为16.66ms左右sw渲染程序设置,因硬件而异。渲染也会受主线程忙碌程度的影响,由于渲染线程和JS执行线程是互斥的,在JS执行线程结束前主线程不会去调起渲染线程。

但有时渲染过程中的recalculatestyle、layout会被提早,而不是等抵达渲染时机再执行。例如更改了layout相关款式后,未到渲染时机就对layout相关属性进行了读取,则浏览器会立即执行recalculatestyle和layout来返回确切的layout信息。

硬件加速

浏览器会按规则把页面分为多个视口。满足个别规则的节点会升级为合成层,交由GPU勾画,即硬件加速。最终呈现的页面是多个视口复合的结果。合成层上的个别式样变动只需重画这个层,再把各层重新复合即可。

节点升级为合成层的情况有:

使用合成层能提升页面动漫性能,但其创建须要额外开支,应结合实际须要合理借助。

结合反例

创建一个div为反例,在body的click风波对div进行更改

// 创建测试div
const div = document.createElement('div');
div.style.cssText = 'width: 100px; height: 100px; background: red';
document.body.appendChild(div);

图片[2]-CSS属性的渲染步骤及应用渲染方法-唐朝资源网

// 对div样式进行修改 document.body.addEventListener('click', () => { // ... });

在click反弹中,分别采用如下代码来测试,用chrome的performance工具剖析结果。一个task条表示一轮风波循环,一个frame条表示实际一帧图象的持续时间。

1、单次渲染

document.body.addEventListener('click', () => {
  div.style.height = '110px'; // step 1
});

一个基本的渲染反例,step1以后浏览器执行了完整的5个渲染步骤。

2、多轮task下的渲染

document.body.addEventListener('click', () => {
  div.style.height = '110px'; // step 1
  setTimeout(() => {
    div.style.height = '120px'; // step 2
    setTimeout(() => {

      div.style.height = '130px'; // step 3
    });
  });
});

同反例1,step1以后sw渲染程序设置,浏览器同样执行了完整的5个渲染步骤。

但step2执行后并没有渲染,直至step3执行后的一段时间才渲染,由于这时才抵达渲染时机。

从frames栏看见,从step2执行到step3执行到再度渲染的这14.0ms期间,页面上显示的仍然是110px的div,执行完第二次渲染后,直接变为130px的div。

3、提前读取layout相关属性

document.body.addEventListener('click', () => {
  div.style.height = '110px'; // step 1
  console.log(div.offsetHeight);
  setTimeout(() => {
    div.style.height = '120px'; // step 2
    console.log(div.offsetHeight);
    setTimeout(() => {
      div.style.height = '130px'; // step 3
      console.log(div.offsetHeight);

图片[3]-CSS属性的渲染步骤及应用渲染方法-唐朝资源网

}); }); });

对事例2稍加改动,在每位step前面都加上了对layout属性的读取。

结果是每次读取时,假若renderflag为true,浏览器就会立即强制执行style和layout来保证返回正确的数据。但仅提早了这2个步骤,后续步骤不变。

4、仅更改非layout相关属性

document.body.addEventListener('click', () => {
  div.style.background = '#123'; // step 1
  setTimeout(() => {
    div.style.background = '#456'; // step 2
    setTimeout(() => {
      div.style.background = '#789'; // step 3
    });
  });
});

把事例2中对div的height属性改动弄成对background属性(非layout相关属性)改动。

图片[4]-CSS属性的渲染步骤及应用渲染方法-唐朝资源网

结果渲染过程跳过了layout这一步。

5、使用合成层

document.body.addEventListener('click', () => {
  div.style.transform = 'scaleY(1.1)'; // step 1
  setTimeout(() => {
    div.style.transform = 'scaleY(1.2)';  // step 2
    setTimeout(() => {
      div.style.transform = 'scaleY(1.3)';  // step 3
    });
  });
});

把事例2中对div的height属性改动弄成对tansform属性(合成层属性)改动。

执行step1后,第一次渲染仍然是5步完整的渲染步骤,由于此前div没有transform属性,还处于大图层中,此次渲染后才把div提高为合成层。

第二次渲染时,div早已是合成层,对合成层的transform改动不会影响其他视口,渲染过程跳过了layout和paint。

6、使用requestAnimationFrame控制时机

document.body.addEventListener('click', () => {
  div.style.height = '110px'; // step 1

图片[5]-CSS属性的渲染步骤及应用渲染方法-唐朝资源网

requestAnimationFrame(() => { div.style.height = '120px'; // step 2 requestAnimationFrame(() => { div.style.height = '130px'; // step 3 }); }); });

把事例2中各step的执行时机从setTimeout反弹改为requestAnimationFrame(以下简称rAF)反弹。rAF反弹中的任务会在下个渲染时机执行。

step1执行完后抵达第一个渲染时机时,浏览器先执行了style&layout,接着不是执行layer,而是执行rAF任务(执行step2并新增一个rAF任务),再重新进行渲染。之后是等到第二个渲染时机,执行第二个rAF任务(执行step3),再进行渲染。

使用rAF取代定时器来实现动漫,能保证rAF任务中的改动结果一定会被渲染,由于rAF任务的执行和渲染的频度是同步的,不会像反例2中step2的改动被忽视,因而有更流畅的动漫表现。其实这儿讨论的是用JS去改款式,倘若能直接用CSS的animation取代疗效更佳。

7、阻塞渲染

document.body.addEventListener('click', () => {
  div.style.height = '110px'; // step 1
  let i = 0;
  while (i++ < 100000000) {}
});

一轮task中若果进行了长历时的估算,浏览器会仍然等到估算完成才执行渲染,这会造成一帧图象持续的时间过长,也就是页面卡顿现象。

可以通过把任务分拆到多个task分段执行,或放在webworker执行来解决。

小结

© 版权声明
THE END
喜欢就支持一下吧
点赞74赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容