banner

CSS 书写顺序

书写顺序

遵循浏览器渲染顺序,减少浏览器 reflow(回流),提升浏览器渲染 dom 的性能。

定位属性的修改会导致 reflow,改变文字颜色、背景等会使得浏览器 repaint,都会影响浏览器渲染性能。

单个样式规则下的属性在书写时,应按功能进行分组,组之间需要有一个空行,并以如下顺序书写,提高代码的可读性。

Content > Positioning Model > Box Model > Typographic > Visual

0. Content 属性

Content 代表文档内容

{
  content
}

1. Positioning Model 位置布局相关属性

Positioning Model 处在首位,因为它会使元素脱离正常文本流,并且覆盖 Box Model (盒模型)相关的样式

{
  position
  top, right, bottom, left
  z-index
  display
  float
  clear
}

2. Box Model 盒模型相关属性

Box Model 紧跟其后,因为它决定了元素的大小和位置

{
  width
  height
  padding
  margin
  border
  overflow
}

3. Typographic 文本排版相关属性

TypographicVisual 不会对前面文档流布局、大小、位置产生影响,只在组件内部起作用,所以排在后面

{
  font
  line-height
  text-align
  word-wrap
}

4. Visual 视觉外观相关属性,包括:color, background, list-style, transform, animation

{
  color
  background
  list-style
  transform
  animation
}

浏览器渲染流程

文档加载完成到完全显示之间浏览器的渲染流程为:

1)浏览器解析 html 构建 dom 树,解析 css 构建 cssom 树即 css rule tree:将 html 和 css 都解析成树形的数据结构; dom 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。

2)构建 render 树:dom 树和 cssom 树合并之后形成 render 树。为了构建 render 树,浏览器大体完成了下列工作:从 dom 树的根节点开始遍历每个可见节点。对于每个可见节点,为其找到适配的 cssom 规则并应用它们。发射可见节点,连同其内容和计算的样式。渲染树中包含了屏幕上所有可见内容及其样式信息。

3)布局 render 树:有了 render 树,浏览器已经知道网页中有哪些节点,各个节点的 css 定义以及它们的从属关系,接着就开始布局,计算出每个节点在屏幕中的位置和大小。(html 采用了一种流式布局的布局模型,从上到下从左到右顺序布局,布局的起点是从render 树的根节点开始的,对应 dom 树的 document 节点,其初始位置为 (0,0),详细的布局过程为:每个 renderer 的宽度由父节点的 renderer 确定。父节点遍历子节点,确定子节点的位置 (x,y),调用子节点的 layout 方法确定其高度,父节点根据子节点的 height, margin, padding 确定自身的高度)

4)渲染、绘制render树:浏览器已经知道了哪些节点要显示,每个节点的 css 属性是什么,每个节点在屏幕中的位置是哪里。就进入了最后一步,按照计算出来的规则,通过显卡把内容画在屏幕上。

浏览器并不是一获取到 css 样式就立马开始解析而是根据 css 样式的书写顺序按照 dom 树的结构分布 render 样式,完成第(2)步,然后开始遍历每个树节点的css样式进行解析,此时的 css 样式的遍历顺序完全是按照之前的的书写顺序,在解析过程中,一旦浏览器发现某个元素的定位变化影响布局,则需要倒回去重新渲染。

例如 css 样式:

{
  width: 100px;
  height: 100px;
  background-color: red;
  position: absolute;
}

当浏览器解析到 position 的时候突然发现该元素是绝对定位元素需要脱离文档流,而之前却是按照普通元素进行解析的,所以不得不重新渲染,解除该元素在文档中所占位置,然而由于该元素的占位发生变化,其他元素也可能会受到回流的影响而重新排位,最终导致(3)步骤花费时间太久而影响到(4)步骤的显示,影响了用户体验。

render 树的结构不等同于 dom 树的结构,一些设置 display: none 的节点不会被放在 render 树中,但会在 dom 树中。

有些情况,比如修改了元素的样式,浏览器并不会立刻回流 (reflow) 或重绘 (repaint),而是把这些操作积攒一批,然后做一次 reflow,这也叫做异步 reflow。但是在有些情况下,比如改变窗口大小,改变页面默认字体等浏览器会马上进行 reflow。

为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现在屏幕上,并不会等到所有 html 都解析完成之后再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,可能还在网络上下载其余内容。

归档 分类 标签 关于