css样式表加载会造成阻塞吗?

510 阅读2分钟

先抛出结论

  1. css加载对dom树方面:
  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  1. css加载对js语句方面:
  • css加载会阻塞后面js语句的执行

css加载与dom树关系

首先我们先把浏览器中的资源加载速度限制为slow 3G

    <html lang="en">
    <head>
        <meta charset="UTF-8">
    </head>
    <script>
        setTimeout(() => {
            console.log(document.getElementById('app'));
        })
    </script>
    <style>
        #app{
            background-color: orange;
        }
    </style>
    <!--引入在线的element ui样式-->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <body>
    <div id="app">
        App
    </div>
    </body>
    </html>

假设: CSS加载会阻塞DOM树解析和DOM树渲染 那么elementui.css还没加载完之前是不会在控制台打印app节点并且页面不会渲染app节点.

结果: 打印了app节点, 但是渲染出来必须等到css文件加载完毕, 所以结论为不影响dom树解析但是阻塞dom树渲染.

原因: 因为加载css的时候后面可能还会会修改下面DOM节点的样式. 如果css加载不阻塞DOM树渲染的话,那么当css加载完之后,DOM树可能又得重新重绘或者回流了,这就造成了一些没有必要的损耗。所以先把DOM树的结构先解析完,把可以做的工作做完,然后等css加载完之后,在根据最终确定的样式来渲染DOM树减少不必要的渲染操作.

优化效果分析: 假设css加载不阻塞渲染可能导致的结果.

<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<link rel="stylesheet" href="./css/a.css">
<link rel="stylesheet" href="./css/b.css">
<body>
<div id="app">
    App
</div>
</body>
</html>

案例中 a b两个css文件都会对app元素进行样式更换(目的是用b.css样式覆盖a.css样式) 如果link不阻塞dom渲染那么当a.css加载完成后页面就会渲染一次, 当b.css加载完成后也会渲染一次造成了不必要的性能浪费

css加载会阻塞后面的JS

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script>
        console.log('before css');
        let start = new Date();
    </script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" rel="stylesheet">
    <script>
        console.log('after css');
        let end = new Date();
        console.log(end - start);
    </script>
</head>
</html>

// 等待css加载完成后才会去打印
before css
after css
11553ms

image.png 打印时间和加载时间基本对上了, 可以证明link css加载会阻塞后面的js语句执行

根据link css加载的特点进行优化

  1. 使用CDN加载来加载提速
  2. 合并多个css文件减少http请求
  3. 压缩css文件例如使用webpack开启css压缩

结尾

css样式除了通过link引入也可以通过style标签进行修改, 那么这两者有什么区别呢?链接走起~