浏览器渲染进程,解决前端面试

前言

复习浏览器原理这一块的浏览器渲染过程

浏览器渲染过程

这个过程是

  1. 解析HTML,生成Dom树
  2. 解析CSS,生成Style Rules
  3. 接着HTML和CSS进行结合,生成渲染树Render Tree
  4. 之后通过计算每一个元素的大小,位置,给出每个节点所应该出现的屏幕精确坐标,从而得到基于渲染树的 布局渲染树Layout of the render tree)。
  5. 遍历渲染树,将每个节点用 UI 渲染引擎来绘制,从而将整棵树绘制到页面上,这个步骤叫 绘制渲染树Painting the render tree

重绘

元素样式发生改变,并不涉及到位置发生改变。这个影响的是上面的步骤五

会引起重绘的: color、background-color、visibility

回流(重排)

元素的尺寸、结构、位置发生了改变会引起回流。涉及一些width、height、padding、margin、left、top之类的会触发回流。

引起回流的:

  • 页面首次渲染
  • 浏览器窗口大小发生改变
  • 元素尺寸或位置发生改变
  • 元素内容变化(文字数量或图片大小等等)
  • 元素字体大小变化
  • 添加或者删除可见DOM元素
  • 激活CSS伪类(例如::hover
  • 查询某些属性或调用某些方法

注意

  1. 回流的代价比重绘的要大,当一个元素的位置发生了改变,旁边的元素可能会相应地位置发生改变,但是当一个元素的样式发生改变,不会引起其他元素样式的改变。

  2. 但是现在浏览器对这个进行了优化: 浏览器会把所有的重绘和重排这些任务放到一个队列里面,等到了一定的时间或者数量的话就会对这些任务进行批量处理。这样就大大减少了重绘和重排的次数。

ini 复制代码
div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';

这种只需要触发一次重排

  1. 当遇到offsetWidth、offsetHeight、clientWidth、clientHeight、scrollTop、scrollWidth这些的时候,因为需要及时计算出来的,所以浏览器需要重新进行布局计算,所以之前的队列里面的任务将会清空。
ini 复制代码
div.style.left = '10px';
console.log(div.offsetLeft);
div.style.top = '10px';
console.log(div.offsetTop);
div.style.width = '20px';
console.log(div.offsetWidth);
div.style.height = '20px';
console.log(div.offsetHeight);

他就是需要每次立即执行重排或者重绘,所以需要触发4次重排+重绘

降低重绘和回流的方法

CSS:

  1. 避免使用Table布局
  2. 避免设置多层内联样式
  3. 避免使用CSS表达式(例如:calc()
  4. 使用 visibility 替换 display

JS:

  1. 使用类名对样式逐条更改
ini 复制代码
const div = document.querySelector('.myDiv')
div.style.width = '100px'
div.style.height = '100px'
div.style.border = '1px solid blue'

这样会多次触发重绘和重排,应该

css 复制代码
.myDiv{
    width:100px;
    height:100px;
    border:1px solid blue;
}
duv.classList.add('myDiv')
  1. 缓存对敏感属性值的计算

有些场景我们需要多次计算来获取元素在页面的布局位置

ini 复制代码
const list = document.querySelector('.list')
for(let i = 0;i < 10;i++){
    list.style.top = `${list.offsetTop + 10}px`
    list.style.left = `${list.offsetLeft + 10}px`
}

这个计算属性会导致触发布局重新计算,所以消耗的性能会很大,需要对它进行缓存

ini 复制代码
const list = document.querySelector('.list')
let offsetTop = list.offsetTop,offsetLeft = list.offsetLeft
for(let i = 0;i < 10;i++){
    offsetTop += 10
    offsetLeft += 10
}
list.style.top = offsetTop
list.style.left = offsetLeft
  1. 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
ini 复制代码
dom.display = 'none' 
// 修改dom样式 
dom.display = 'block'

4.position属性为absolute或fixed:重排开销比较小,不用考虑它对其他元素的影响

最后

感谢观看

相关推荐
也无晴也无风雨39 分钟前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
不二人生5 小时前
SQL面试题——连续出现次数
hive·sql·面试
郝晨妤5 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui