用图层取胜
目标
编写一个使用 @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
它会为每个声明显示层、媒体条件、特异性、顺序,并在最上面输出层的顺序。遇到无法处理的选择器时,不会悄悄跳过,而会明确说“无法解析”。
步骤
- 把
@layer reset, base, components, utilities;放在最上面 - 填充四个层,并确认后面的层获胜
- 层外的规则即使特异性较低也会获胜 →
03-predict.txt !important会颠倒顺序 →04-predict.txt- 用
:where()得到特异性为 0 的默认值 - 工具类无需特异性就能战胜组件
- 把计算器的结果保存为
07-resolve.txt - 去掉层外的
!important - 总结 →
09-notes.md
参考
- 这个计算器能处理
:where()和:is(),但不能处理括号内含有组合器的选择器。请像:where(.title)这样只放一个。 - 请先写预测文件,再运行计算器。如果颠倒顺序,学到的东西就没了。
把层的顺序钉死
创建 /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。样式表也必须仍然通过前面步骤的标准。
核心只有一点——在排序顺序中,层叠层排在特异性之前。 前面分出了胜负,后面就不再看,这是贯穿整个层叠的规则。