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

前言

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

浏览器渲染过程

这个过程是

  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:重排开销比较小,不用考虑它对其他元素的影响

最后

感谢观看

相关推荐
passerby60611 天前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 天前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 天前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 天前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 天前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 天前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅1 天前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊1 天前
jwt介绍
前端
爱敲代码的小鱼1 天前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte1 天前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc