理解 CSS 规则之间的优先级关系

如果理解了 CSS 规则之间的优先级关系,那么,HTML+CSS 就算基本掌握了。
再稍微花些心思和时间,将页面从视觉设计变成源代码的实现过程,就不会存在太大的问题。

一个元素,多条规则,如何渲染?

CSS 的规则,说简单也简单,说不简单也不简单,但它的底层说起来应该属于很简洁的。
有一条颠簸不破的现实: 保持简洁,一旦操控不当,就会变得非常混乱。这种混乱,会导致一种毫无技术含量的复杂

有些项目中,我们在完成对应的视觉渲染引擎时,会考虑兼容 CSS 的规则,比如绘制 PDF、绘制 GUI 界面,这样的兼容,会让使用者以很低的成本,获得比较不错的视觉(样式)呈现。
这就引出一个问题: 如果重写一套兼容 CSS 规则的引擎,你会考虑如何实现呢?
一般会是: 1,将当前的 CSS 样式,拆分成一条条的规则;2,然后解析当前的 (DOM) 元素时,看它符合(多条)哪些规则(一个列表);3,然后再在这个规则列表中,找到优先级最高的。

注: 『找到优先级最高的』,在实际代码过程中,可能是从优先级最低的规则开始分析,然后依次找下一个优先级稍高的规则,相同属性进行覆盖,这样最后存活的就是优先级最高的了。

理解 CSS 规则的优先级

我们已经意识到一个问题,同一个 DOM 元素,可能会有多条 CSS 规则对应到,每个规则内的某个属性(比如 color、font-size) 可能是不一样的,这样就存在冲突了。
冲突的时候,听谁的?优先级是如何确定的?

『开始 HTML』 的 Demo 站点基础上 (在 FirstWeb 中重新选中对应的站点目录),我们以其基本的 HTML 片段为例,来理解 CSS 规则的优先级问题。
使用方式:

  1. 下面的小段 HTML 片段,要心里有底。如果没有,代码截图后再新窗口打开图片进行对照。
  2. 后面提到的 CSS 代码,可直接复制、粘贴到 style.css 末尾,粘贴前应去掉上次尝试时留下的代码。
  3. 根据自己的想法,再尝试做一些调整,比如增加其它属性 font-size、font-weight、letter-spacing、line-height .etc
<div class="cover">
    <div class="container">
        <h1 id="caption">你好,世界 <span class="alt">alt-one</span></h1>
        <h2>我是一个描述 <span class="alt">alt-two</span></h2>
    </div>
  </div>

调整 alt 文字的样式

增加一段 CSS:

.cover .alt{
  color: red;
  font-size: 12px;
}

会获得如下效果:

这很好理解,因为 alt-onealt-two 都有一个相同的 class 叫 alt,而且 DOM 层级结构都是 .cover > .container > .alt ,所以上面这个 CSS 规则会同时对两者起作用。
我们在之前就说过 Namespace(空间),虽然 .cover .alt 一般它被叫做CSS选择器,而一定程度上就是一个 空间,可以跟其它的规则有效区分(比如在 .cover 外部还有 class 叫 alt 的,那么它是不会生效的)。


这时,我们应该会产生一个疑问: 上面 CSS 规则中,用 .cover .container .alt 会不会比 .cover .alt 更好?
从工程的角度,答案为是的。但实际情况下,如果并不与其它逻辑混淆,使用 .cover .alt 会更短一些,也挺好的。
继续探讨,如果两个 空间 同时存在并且冲突,哪个会最终生效呢?

.cover .alt{
  color: red;
  font-size: 12px;
}
.cover .container .alt{ /*优先级高于 .cover .alt */
  color: blue;
}

效果如下: 1,字体大小都起作用了;2,字体颜色只有 blue 起作用。
这就涉及到规则的优先级问题了。
.cover .alt.cover .container .alt,哪个更优先?后者优先,因为它的范围定义得更具体、更小,同样指定了 color 的两条规则中,优先级高的生效。


如果我们在某属性声明后,末尾增加 !important,那么它的优先级会更高。 如下文代码所示,这时 .cover .altcolor 的声明,优先级就高于 .cover .container .alt 了。一般情况下,需要避免使用 !important ,因为容易导致代码逻辑变乱;但事无绝对,看场合用起来也是推荐的。

.cover .alt{
  color: red !important; /*强制调高当前属性的优先级*/
  font-size: 12px;
}
.cover .container .alt{ 
  color: blue;
}

效果如下:


前面,我们提到 .cover .alt 相当于一个 空间 的存在,而 空间 是可以细分下去的。
.cover .alt 可以对 alt-one & alt-two 两个同时生效,alt-oneh1 中,而 alt-twoh2 中,所以,针对 alt-two 还可以额外赋予规则。

.cover .alt{
  color: red;
  font-size: 12px;
}
.cover h2 .alt{
  color: blue;
}

效果如下:

在实践中,如何处理优先级?

之所以存在优先级的问题,其实也在说明 CSS 样式规则之间是存在冲突的。
在解决冲突上,有一个非常巧妙的办法,就是: 不要有冲突就好!

不是开玩笑。
一般并不需要去特别记忆,哪个规则为什么会最优先呈现,因为:

  1. 实际动手写代码了,写得多了,就有这种直觉了。
  2. 真的优先级产生了冲突,Debug 下,调整一下也很快。

关于优先级的『直觉』,其实也简单,应该优先级高的就应该优先级高,比如:

  1. 『选择器』层级描述更完整的自然优先级高
  2. 指定了 ID 的 (以 # 开头的选择器),自然比没有 ID 的优先级高

另外,所谓的『冲突』,其实都算是『 Namespace(空间)』上的冲突,如果构建 HTML 页面的基本结构以及写 CSS 规则时,已经基本建立了有效的空间区隔,就能避免大部分的冲突

但是,有冲突也没有关系,因为:

  1. 代码是改出来的;
  2. 继承(父)规则后再进行细节的调整、处理冲突,这很常见,是对 冲突 的善用。

最后

在 『第一次写代码』中,里面使用的 HTML 结构是 <div class="cover"> <div class="container"></div> </div>,是为了引出一个问题,作为 containercover 包裹,从语义上分析,是否合适呢?如果 .cover 替换为 .cover_container, 是否会更合适呢?

大象无形,菩萨无相。
我认为这些并不重要。后续,你也一定会遇到,从语义上分析这种逻辑,有它的道理,但你只要有自己的道理就可以了,因为,并不影响最终的呈现结果。
重要的是,形成并接受自己的风格,不混乱就可以,但这也要一个比较漫长的积累过程。
当然,不接受我的观点也很 OK,我们只要知道此处存在这个问题,就可以了。

代码如何写,也是个人的倾向,写代码有时候就像是一种 整理方式,这里允许每个人有自己的偏好。