面试题: 回流和重绘及解决方法~~~

119 阅读2分钟

浏览器渲染页面顺序:

  1. 先解析html标签结构 ---> DOM树 + 与此同时,解析css样式表 ---> 样式规则
  2. 将DOM树和css规则合并成一颗渲染树
  3. 布局:计算标签的大小\位置
  4. 喷绘:给标签添加背景颜色\文字颜色\字体大小..
  5. 浏览器将喷绘好的内容显示在网页中也就是我们用户所看到的页面;

回流:

  • 回流: 通过JS经常会改变标签大小\位置...需要重新来布局就造成了回流;
  • 重绘: 给标签添加背景颜色\文字颜色.... 需要重新喷绘就造成了重绘;
  • 重点: 回流必重绘,重绘不一定回流;
1. 重绘不会引起dom结构和页面布局的变化,只是页面样式的变化;有重绘不一定有回流;
2. 而回流会引起dom结构和页面布局的变化,有回流就一定有重绘。

回流和重绘所带来的问题:

  • 回流和重绘多次使用会导致浏览器加载页面速度变慢,影响性能;

尽量减少回流和重绘的解决办法:

  • 方法1: 合并样式修改:
1.标签.style.cssText= "";
2.将所有样式合并到一个类名下进行操作;
function setStyle(ele, obj) {
        var cssText = ''
        for(var key in obj) {
            cssText += key + ':' + obj[key] + ';'
            // ele.style[key] = obj[key]
        }
        ele.style.cssText = cssText
    }

    setStyle(div, {
        width: '',
        height: '',
        left: '',
        top: '',
    })
  • 方法2: 减少dom操作造成的回流
1.将ul隐藏,操作dom,再显示它
2.克隆ul,对克隆出来的ul操作,用克隆出来的ul替换原本的ul
3.利用碎片文档

给ul中添加10个li
    // ul.style.display = 'none'
    // var newUL = ul.cloneNode(true)
    var fg = document.createDocumentFragment()
    for(var a = 0; a < 10; a++) {
        var li = document.createElement('li')
        // ul.appendChild(li)
        // newUL.appendChild(li)
        fg.appendChild(li)
    }
    // ul.parentElement.replaceChild(newUL, ul)
    ul.appendChild(fg)
  • 方法3: 将定时器中可能造成回流的操作放到定时器外;
setInterval(() => {
        var left = box.offsetLeft
        left += 2
        box.style.left = left + 'px'
    }, 500)
 
    var left = box.offsetLeft
    setInterval(() => {
        left += 2
        box.style.left = left + 'px'
    }, 500)