优化实战 第 06 期 - 页面渲染以及重排重绘

1,557 阅读2分钟

用户使用浏览器一般会打开多个页面,现代浏览器使用单独的进程 Render Process 渲染每个页面,以提升页面性能和稳定性

render_process.png

页面的渲染

  • 渲染图示

    render.jpeg

  • 渲染图解

    根据 HTML 标记 解析出 DOM 树

    根据 CSS 样式 解析出 CSS 规则树

    根据 DOM 树CSS 规则树 生成 渲染树

    根据渲染树计算 DOM 节点的信息(节点的大小、位置等)

    根据计算好的信息绘制页面(颜色、背景、字体等)

重绘和回流

  • 重绘(repaint)

    DOM 元素的外观属性发生变化时,如:字体颜色或背景颜色

    浏览器会重新绘制受影响的元素到屏幕,这个过程称之为重绘

  • 回流(reflow)

    DOM 元素的几何属性发生变化时,如:盒子模型相关的属性。其周围元素的位置也会受到影响

    浏览器会重新生成渲染树且重新布局,这个过程称之为回流

  • 影响关系

    重绘不一定导致回流,但回流一定会导致重绘

常见重绘、回流以及优化方案

  • 常见场景

    浏览器的窗口大小改变(resize 事件)

    添加或删除可见的 DOM 元素(必要的 DOM 操作)

    页面中的内容发生变化

  • 优化方案

    使用 document.createDocumentFragement() 优化必要的 DOM 操作

    使用 opacitytransform3D转换属性 开启动画的 GPU 加速

    使用 el.style.cssText 替代 el.style 来集中改变样式

    使用 textContent 替代 innerText 来动态修改页面中的内容

    使用 will-change 属性提前通知浏览器元素将要做什么,让浏览器提前准备合适的优化机制,增强页面的动画渲染性能

滑动选项卡

  • 基本结构

    <div class="tab" id="tabId">
      <ul class="tab-nav">
        <li class="slider" role="slider"></li>
        <li data-index="0">导航项</li>
      </ul>
      <div class="tab-content">
        <div>滑动内容</div>
      </div>
    </div>
    
  • 布局技巧

    .tab {
      overflow: hidden;
    }
    .tab-nav > .slider{
      transition: left .3s ease;
    }
    .tab-nav:hover {
      will-change: margin-left;
    }
    .tab-content {
      display: flex;
      width: 100%;
      transition: margin-left .3s ease;
    }
    .tab-content > div {
      flex-shrink: 0;
      width: 100%;
    }
    

    flex-shrink 定义元素占多余空间的缩小比例(子元素的宽度和大于父元素的宽度时起作用),默认值为 1 ,即空间不足时,元素都将等比例缩小

    如果 flex-shrink 的属性设为 0 时,则空间不足时不进行缩小

  • 绑定事件实现滑动

    const tabId = document.querySelector('#tabId')
    const tabNav = tabId.querySelector('.tab-nav')
    const tabSlideBar = tabId.querySelector('.slider')
    const tabSlideContent = tabId.querySelector('.tab-content')
    tabNav.addEventListener('click', event => {
      const index = event.target.dataset.index
      tabSlideBar.style = `left: ${event.target.offsetLeft}px;`
      tabSlideContent.style = `margin-left: -${index * 100}%;`
    })
    
  • 一起交流学习

    加群交流看沸点