CSS渲染原理 及 优化
对于绝大部分的开发者来说,css的功能就是完成页面布局,制定页面的展示效果。其实css也有许多能实现Web性能优化的方法,接下来我们就一起看看有哪些方法。
![](https://img.haomeiwen.com/i8646214/82ce92dd4ac56a05.jpg)
浏览器渲染原理
- 浏览器在接收到服务器返回的html页面后,
- 浏览器开始构建DOM树
DOM TREE
,遇到CSS样式会构建CSS规则树CSS RULE TREE
, - 遇到
javascript
会通过DOM API
和CSSDOM API
来操作DOM Tree
和CSS Rule Tree
,解析完成后, - 浏览器引擎会通过
DOM Tree
和CSS Rule Tree
来构造Rendering Tree
(渲染树), - 最后,渲染树构建完成后就是 "布局" 处理,也就是确定每个节点在屏幕上的确切显示位置
- 下个步骤(渲染之后),开始 "绘制" ,遍历渲染树,并用UI后端层,将每一个节点绘制出来。
整个流程如下图所示
![](https://img.haomeiwen.com/i8646214/c6a28b94fa802b8e.png)
css 渲染规则
css的渲染规则,是从上到下,从右到左渲染的。
.main h4 a { font-size: 14px; }
渲染过程是这样的:首先先找到所有的 a,沿着 a 的父元素查找h4,然后再沿着 h4,查找.main。中途找到了符合匹配规则的节点就加入结果集。如果找到根元素的 html 都没有匹配,则这条路径不再遍历。下一个 a 开始重复这个查找匹配,直至没有a继续查找。
浏览器的这种查找规则是为了尽早过滤掉一些无关的样式规则和元素。
css选择器权值
权值,代表着优先级,权值越大,优先级越高。同种类型的选择器权值相同,后定义的选择器会覆盖先定义的选择器。
- important最高
- 内联: 1000
- ID: 100
- Class:10
-
Tag: 1
注: 组合使用,权值会叠加
影响DOM树构建的因素
- HTML响应流被阻塞在网络中
- 有加载未完成的脚本
- 遇到
<script>
, 但是此时还有未加载完的样式文件
页面渲染与执行过程:
通过一个例子,我们来详细看看页面渲染和执行过程到底是怎么工作的:
html代码
<html>
<body>
<link href="example.css" rel="stylesheet">
<div>Hi here</div>
<script>
document.write('<script src="other.js"><scr' + 'ipt>')
</script>
<div>Hi again</div>
<script src="last.js"></script>
</body>
</html>
- 解析器遇到了
example.css
,并将它从网络中下载下来。下载样式表的过程是耗时的,但是解析器并没有被阻塞,继续往下解析 - 解析器遇到
<script>
标签,但是由于样式文件下载未完成,阻塞了该脚本的执行(上面已指出)。解析器(构建DOM树和 CSS规则树)被阻塞住,不能继续往下解析 - 因为渲染树是DOM树 和 CSS规则树 来构造,所以此时,渲染树的构建也被阻塞
- 渲染树是绘制触发条件之一,因此
Hi there!
也就 不能被绘制(painting->display)
到页面中。
绘制的触发条是: 渲染树构建完成,并遇到了阻塞
- 接下来,一旦
example.css
下载完成,内联的脚本执行完了之后,解析器开始执行遇到的<script>
标签,并查到src
属性中的other.js
文件,立即被阻塞,开始下载other.js
; - 因为解析器被阻塞,触发了绘制条件,浏览器就会收到绘制的请求,“Hi,here”就会显示在页面上
-
other.js
加载完成了之后,解析器继续向下解析,遇到last.js
之后又被阻塞, - 因为解析器再次被阻塞,又形成了 “绘制” 条件,因此绘制DOM树的内容,即,“Hi,again”就会显示在页面上。
-
last.js
加载完成,并且被执行。
做了以上了解以后,我们再来说说应该怎样优化css性能
优化你的css
1. 把 Stylesheets 放在 HTML 页面头部
浏览器在所有的 stylesheets 加载完成之后,才会开始渲染整个页面,在此之前,浏览器不会渲染页面里的任何内容,页面会一直呈现空白。这也是为什么要把 stylesheet 放在头部的原因。如果放在 HTML 页面底部,页面渲染就不仅仅是在等待 stylesheet 的加载,还要等待 html 内容加载完成,这样一来,用户看到页面的时间会更晚。
对于 @import 和 <link> 两种加载外部 CSS 文件的方式:@import 就相当于是把 <link> 标签放在页面的底部,所以从优化性能的角度看,应该尽量避免使用 @import 命令
2. 嵌套层级不要超过三级
一般情况下,嵌套层级不要超过三级,过渡的嵌套会导致代码变得臃肿,导致css文件体积变大,造成性能上的浪费,影响渲染的速度;css层级太多,也过于依赖html DOM结构,不易于维护。如果层级比较深,就直接定义一个class代替多余的层级。
3. css 命名规范,书写规范。
4. 多用继承属性
尽量的继承父类样式 ,重复的定义会造成很多不必要的性能浪费。
5. 少用滤镜,好用hack,少用position: absolute;
6. 使用简写样式。见下例
.mg {
margin-top: 20px;
margin-right: 0px;
margin-bottom: 20px;
margin-left: 100px;
}
可以简写为
.mg {
margin: 20px 0px 20px 100px;
}
7. 不要再id选择器和class选择器前使用标签名 例如:
div #box {
color: white;
}
id选择器本身就能唯一确定一个元素,没必要再在前面加上标签名。同样,类选择器也是,如果需要给某个标签的类增添额外的样式,建议使用另一个类名。这种情况下,也可以使用 div .box{}
形式,差别不大。
8. 平铺的背景图片不要过小,1px的图片平铺长宽25px的区域块,需要2500次,太影响渲染速度。
9;谨慎使用float,具体细节请参考我的另一片文章 《深入理解f浮动与清除浮动》
10. 合理化布局(模块化布局)
可以把样式划分为”基类“ 和 “扩展类”; 把模块基本相同的样式写在基类里,不同的再重新用class定义,写在扩展类中。
11 尽量少用通配符,只用通配符设定一切基础的样式,如:
* {margin:0; padding:0;}
本文就讲到这里,如果有错误,欢迎大家指正。