回流重绘

渲染优化 - 图1

  • 重排(回流)Reflow: 添加元素、删除元素、修改大小、移动元素位置、获取位置相关信息
  • 重绘 Repaint:页面中元素样式的改变并不影响它在文档流中的位置。
  1. clientTopclientLeftclientWidthclientHeight
  2. offsetTopoffsetLeftoffsetWidthoffsetHeight
  3. scrollTopscrollLeftscrollWidthscrollHeight
  4. getComputedStyle()
  5. getBoundingClientRect
  6. // 以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列,触发回流重绘来返回值

现在的浏览器已经非常完善了,会自动帮我们做一些优化。当我们用js操作DOM的时候,浏览器并不是立马执行的,而是将操作存储在一个队列中。当达到一定数量或者经过一定时间以后浏览器再统一的去执行队列中的操作。那么回到我们刚才的问题,为什么查询这些属性也会导致重排?因为当你查询这些属性时,浏览器就会强制刷新队列,因为如果不立马执行队列中的操作,有可能得到的结果就是错误的。所以相当于你强制打断了浏览器的优化流程,引发了重排。 链接:https://juejin.cn/post/6844904119430283271

我们应当尽可能减少重绘和回流

减少重排和重绘

  • 合并对DOM样式的修改

    1. update{
    2. margin: 5px;
    3. border-dadius: 12px;
    4. box-shadow: 1px 3px 4px #ccc
    5. }
    6. const el = document.querySelector('.box')
    7. el.classList.add('update')
  • 如果需要对DOM进行多次访问,尽量使用局部变量缓存该DOM」

  • 避免使用table布局,可能很⼩的⼀个⼩改动会造成整个table的重新布局
  • CSS尽可能扁平化(CSS选择符从右往左匹配查找),避免节点层级过多

  • display: none的属性会触发重排,visibility : hidden的不影响重绘。

  • DOM离线处理,减少回流重绘次数 ```javascript // 通过 documentFragment 创建一个 dom 文档片段, const el = document.querySelector(‘.box’) const fruits = [‘front’, ‘nanjiu’, ‘study’, ‘code’]; const fragment = document.createDocumentFragment(); fruits.forEach(item => { const li = document.createElement(‘li’); li.innerHTML = item; fragment.appendChild(li); }); el.appendChild(fragment);

// 克隆节点,修改完再替换原始节点 const el = document.querySelector(‘.box’) const fruits = [‘front’, ‘nanjiu’, ‘study’, ‘code’]; const cloneEl = el.cloneNode(true) fruits.forEach(item => { const li = document.createElement(‘li’); li.innerHTML = item; cloneEl.appendChild(li); }); el.parentElement.replaceChild(cloneEl,el)

  1. - 脱离普通文档流
  2. - 给图片增加固定宽高
  3. - 使用 CSS3 GPU 加速 [https://www.yuque.com/mewcoder/fe/orupkf](https://www.yuque.com/mewcoder/fe/orupkf)
  4. - 常见的触发硬件加速的css属性:
  5. - transform
  6. - opacity
  7. - filters
  8. - Will-change
  9. <a name="00ac6dcd"></a>
  10. ## <br />
  11. [https://mp.weixin.qq.com/s/rjwB5Re6DsnvO-ZQ3Y-RhQ](https://mp.weixin.qq.com/s/rjwB5Re6DsnvO-ZQ3Y-RhQ)
  12. <a name="lCH1I"></a>
  13. # HTML 优化
  14. 1. 语义化`HTML`: 代码简洁清晰,利于搜索引擎,便于团队开发
  15. 2. 提前声明字符编码,让浏览器快速确定如何渲染网页内容
  16. 3. 减少 HTML 嵌套关系、减少 DOM 节点数量
  17. 4. 删除多余空格、空行、注释、及无用的属性等
  18. 5. HTML 减少`iframe`使用 (`iframe`会阻塞`onload`事件可以动态加载`iframe`)
  19. 6. 避免使用 table 布局
  20. <a name="uJ9G8"></a>
  21. ###
  22. <a name="bhSyU"></a>
  23. # CSS 优化
  24. 1. 减少伪类选择器、减少样式层数、减少使用通配符
  25. 2. 避免使用`CSS`表达式,`CSS`表达式会频繁求值, 当滚动页面,或者移动鼠标时都会重新计算 (`IE6,7`)
  26. ```css
  27. background-color: expression( (new Date()).getHours()%2 ? "red" : "yellow" );
  1. 删除空行、注释、减少无意义的单位、css进行压缩
  2. 使用外链css, 可以对CSS进行缓存
  3. 添加媒体字段,只加载有效的css文件

    1. <link href="index.css" rel="stylesheet" media="screen and (min-width:1024px)" />
  4. CSS contain属性, 将元素进行隔离

  5. 减少 @import 使用,由于 @import 采用的是串行加载

JS 优化

  1. 通过asyncdefer异步加载文件
    渲染优化 - 图2
  2. 减少 DOM 操作,缓存访问过的元素
  3. 操作不直接应用到 DOM 上,而应用到虚拟 DOM 上。最后一次性的应用到 DOM 上。
  4. 使用webworker解决程序阻塞问题
  5. IntersectionObserver

    1. const observer = new IntersectionObserver(function(changes) {
    2. changes.forEach(function(element, index) {
    3. if (element.intersectionRatio > 0) {
    4. observer.unobserve(element.target);
    5. element.target.src = element.target.dataset.src;
    6. }
    7. });
    8. });
    9. function initObserver() {
    10. const listItems = document.querySelectorAll('img');
    11. listItems.forEach(function(item) {
    12. observer.observe(item);
    13. });
    14. }
    15. initObserver();
  6. 虚拟滚动 vertual-scroll-list

  7. requestAnimationFramerequestIdleCallback
    渲染优化 - 图3
  8. 尽量避免使用eval, 消耗时间久
  9. 使用事件委托,减少事件绑定个数。
  10. 尽量使用 canvas 动画、CSS动画