Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器回流、重绘 #75

Closed
PolluxLee opened this issue Jul 30, 2018 · 0 comments
Closed

浏览器回流、重绘 #75

PolluxLee opened this issue Jul 30, 2018 · 0 comments

Comments

@PolluxLee
Copy link
Owner

PolluxLee commented Jul 30, 2018

# 页面的呈现

  • DOM 树: 浏览器把获取到的 HTML 代码解析成1个 DOM 树,HTML 中的每个 tag 都是 DOM 树中的1个节点,根节点就是我们常用的 document 对象
  • 样式结构体: 浏览器把所有样式(用户定义的 CSS 和用户代理)解析成样式结构体
  • Render Tree: DOM Tree 和样式结构体组合后构建 Render Tree,其中每个节点都称为 Box,理解页面元素为一个具有填充、边距、边框和位置的盒子

一旦 Render Tree 构建完毕后,浏览器就可以根据 Render Tree 来绘制页面了

# 回流

当 Render Tree 中部分或全部元素的 尺寸、结构、或某些属性 发生改变时,浏览器重新渲染部分或全部文档的过程称为回流

在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘

(由于浏览器使用流式布局,对 Render Tree 的计算通常只需要遍历一次就可以完成,但 table 及其内部元素除外,他们可能需要多次计算,通常要花 3 倍于同等元素的时间)

# 重绘

当 Render Tree 中的一些元素需要更新属性,而这些属性只是影响元素的 外观,风格,而不会影响布局的,比如 background-color。则就叫称为重绘

回流必将引起重绘,而重绘不一定会引起回流

# 触发回流

当页面布局和几何属性改变时就需要回流:

  • 页面渲染初始化
  • 添加或者删除可见的DOM元素
  • 激活 CSS 伪类(例如::hover)
  • 元素位置改变
  • 元素尺寸改变——边距、填充、边框、宽度和高度
  • 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变
  • 浏览器窗口尺寸改变——resize事件发生时

# 浏览器自身优化

浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会 flush 队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘

但当向浏览器请求某些属性时,浏览器为了给你最精确的值,需要 flush 队列,因为队列中可能会有影响到这些值的操作:

  • clientWidth、clientHeight、clientTop、clientLeft
  • offsetWidth、offsetHeight、offsetTop、offsetLeft
  • scrollWidth、scrollHeight、scrollTop、scrollLeft
  • scrollIntoView()、scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

# 减少回流、重绘

CSS

  • 避免使用 table 布局
  • 尽可能在 DOM 树的最末端改变 class
  • 避免设置多层内联样式
  • 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上
  • 避免使用 CSS 表达式(例如:calc())

JavaScript

  • 避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性
  • 避免频繁操作 DOM,创建一个 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中
  • 也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来

# 参考

http://www.css88.com/archives/4996

https://www.zhangxinxu.com/wordpress/2010/01/%E5%9B%9E%E6%B5%81%E4%B8%8E%E9%87%8D%E7%BB%98%EF%BC%9Acss%E6%80%A7%E8%83%BD%E8%AE%A9javascript%E5%8F%98%E6%85%A2%EF%BC%9F/

https://www.cnblogs.com/snandy/archive/2011/03/12/1980444.html

https://juejin.im/post/5a9923e9518825558251c96a

@PolluxLee PolluxLee changed the title 浏览器回流和重绘 浏览器回流、重绘 Jul 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant