先抛出结论
- css加载对dom树方面:
- css加载不会阻塞DOM树的解析
- css加载会阻塞DOM树的渲染
- 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
打印时间和加载时间基本对上了, 可以证明link css加载会阻塞后面的js语句执行
根据link css加载的特点进行优化
- 使用CDN加载来加载提速
- 合并多个css文件减少http请求
- 压缩css文件例如使用webpack开启css压缩
结尾
css样式除了通过link引入也可以通过style标签进行修改, 那么这两者有什么区别呢?链接走起~