TT Lab
开始
学习 学习路径 课程

CSS — 后写的规则获胜

用图层取胜

在 TT Lab 中继续学习

目标

编写一个使用 @layer 的样式表,并用计算器确认哪个声明获胜。即使没有浏览器,这个答案也只有一个。

为什么重要

在排序顺序中,层叠层比特异性更早分出胜负。所以一旦开始使用层叠层,就会冒出“特异性明明更高,为什么会输?”的问题,如果不知道答案,人们又会回到 !important。

规则只有两行。没有放进层的声明会进入最后一个层;普通声明是后面的层获胜,而 !important 是前面的层获胜。这两行合在一起,层外的普通声明最强,层外的 !important 最弱。

要创建的内容

只有一个文件 /root/work/layers/theme.css,外加两个预测文件。不需要 HTML——评分器会假设存在下面这些元素,并据此求解层叠。

div#app > article.card > h2.title
div#app > article.card > h2.title.u-hidden
div#app > article.card > a.btn.primary
div.toolbar > button.btn

计算器

cd /root/work/layers
python3 /opt/lab/checks/css-layer-lab/layercalc.py theme.css

它会为每个声明显示层、媒体条件、特异性、顺序,并在最上面输出层的顺序。遇到无法处理的选择器时,不会悄悄跳过,而会明确说“无法解析”。

步骤

  1. 把 @layer reset, base, components, utilities; 放在最上面
  2. 填充四个层,并确认后面的层获胜
  3. 层外的规则即使特异性较低也会获胜 → 03-predict.txt
  4. !important 会颠倒顺序 → 04-predict.txt
  5. 用 :where() 得到特异性为 0 的默认值
  6. 工具类无需特异性就能战胜组件
  7. 把计算器的结果保存为 07-resolve.txt
  8. 去掉层外的 !important
  9. 总结 → 09-notes.md

参考

把层的顺序钉死

创建 /root/work/layers/theme.css,并把 @layer reset, base, components, utilities; 写成第一条规则。然后在每个层中至少放入一条规则。

mkdir -p /root/work/layers。层的顺序由名称首次出现的次序决定。在最上面放一行不带块的声明式规则,此后无论哪个文件先被读取,顺序都是固定的。

后面的层获胜

在 base 和 components 两个层中,各放一条作用于 div#app > article.card > h2.title 的 color 规则,并让 components 获胜。这一步不使用 !important。

普通声明是后面的层获胜。不需要提高特异性——因为层叠层这一步比特异性更早分出胜负。请用计算器确认获胜者所在的层名。

层外最强

在 @layer 块的外面写一行标题颜色规则。这个选择器的特异性必须低于 components 规则。然后在 /root/work/layers/03-predict.txt 中写下获胜的位置和获胜的值。

没有放进层的声明会隐式地进入最后一个层。你会看到 0,1,0 战胜了特异性为 1,2,0 的规则——不是计算错了,而是特异性根本没有轮到去看。预测文件中必须包含 레이어 밖(韩文,意为“层外”)这个词和获胜的颜色值。

important 会颠倒顺序

在 reset 层和 components 层中,各放一条作用于 div#app > article.card > a.btn.primary 的 !important 颜色规则。reset 一侧选择器的特异性必须更低。在 04-predict.txt 中写下哪个层获胜以及原因。

普通声明是后面的层获胜,但 !important 是前面的层获胜。规范解释说,这与 important 颠倒来源顺序是同样的逻辑。预测文件中必须包含 reset 和 important。

特异性为 0 的默认值

在 base 层中用 :where() 写标题粗细的默认值,并在同一个层内再放一条带有特异性的粗细规则。:where() 规则在文件中必须位于更靠后的位置。

:where() 的特异性始终是 0,0,0。明明写在后面,却输给了前面的标签选择器,这就证明了胜负是由特异性而不是顺序分出的。括号内请不要带组合器,只放一个。

工具类无需特异性就能获胜

在 utilities 层中放置 .u-hidden { display: none },并在 components 层中放置一条选中同一元素、特异性更高的 display 规则。不使用 !important,工具类也必须获胜。

评分器会计算 div#app > article.card > h2.title.u-hidden 上谁获胜。给工具类加 !important 的做法,有了层叠层之后就不再需要了——只要把工具层声明在组件之后就行了。

用计算器确认

运行 layercalc.py,把结果保存为 /root/work/layers/07-resolve.txt。保存的行数必须与当前样式表的声明数相同,并且必须原样包含层顺序那一行。

python3 /opt/lab/checks/css-layer-lab/layercalc.py theme.css | tee 07-resolve.txt。在开发者工具中看到带删除线的规则时,你在脑子里做的计算就是这个。

去掉层外的 important

整个样式表中不能有层外的 !important。并且要在 components 层中增加 .toolbar > button.btn 的颜色规则,让工具栏按钮的颜色来自 components。!important 加起来不能超过四个。

层外的 !important 会输给所有层中的 !important。本想写成最强,结果成了最弱,这是引入了层叠层的样式表中最常发生的事故。请删掉它,或者移到 reset 里。

为什么特异性轮不到去看

在 /root/work/layers/09-notes.md 中写三行以上(120 个字符以上)。正文中必须包含 레이어(韩文,意为“层”)、특정성(韩文,意为“特异性”)和 important。样式表也必须仍然通过前面步骤的标准。

核心只有一点——在排序顺序中,层叠层排在特异性之前。 前面分出了胜负,后面就不再看,这是贯穿整个层叠的规则。