CSS层叠层 vs BEM vs 实用类:特异性控制
CSS是狂野的,非常狂野。而且很棘手。但今天我们特别要讨论的是特异性问题。
特异性基础
当编写CSS时,几乎不可能没遇到过样式未按预期应用的情况——这就是特异性。你应用了一个样式,它生效了,后来你尝试用不同的样式覆盖它时…毫无反应,它直接无视了你。还是特异性问题。
当然可以使用!important
标志,但像所有前辈开发者一样,这总是有风险的且不被鼓励。完全理解特异性比走这条路要好得多,否则你最终会和自己重要的样式作斗争。
特异性101
许多开发者以不同方式理解特异性的概念。特异性的核心思想是浏览器使用的CSS层叠算法,当两个或多个规则匹配同一元素时决定应用哪个样式声明。
随着项目扩展,特异性挑战也随之增加。假设开发者A添加了.cart-button
,然后按钮样式看起来可以用于侧边栏,但需要微调。后来开发者B添加了.cart-button .sidebar
,从此之后,任何对.cart-button
的更改都可能被.cart-button .sidebar
覆盖,特异性战争就此开始。
不同策略对比
|
|
所有这些方法反映了控制或至少维护CSS特异性的不同策略:
- BEM:通过显式命名简化特异性
- 实用优先CSS:通过保持原子性来绕过特异性
- CSS层叠层:通过分层组织样式来管理特异性
BEM:原始系统
BEM(Block-Element-Modifier)已经存在很长时间了。它是一个编写CSS的方法论系统,强制你明确每个样式层次结构。
|
|
BEM如何处理特异性
|
|
BEM使代码看起来可预测,因为所有选择器都是平等的,使代码更易于维护和扩展。
BEM的不足
- 类名可能变得非常长
- 可能不优先考虑可重用性
- 命名事物成为现实中的痛点
实用类:通过避免处理特异性
这也称为原子CSS。本质上它避免了特异性问题。
|
|
实用优先类的理念是每个实用类具有相同的特异性,即一个类选择器。每个类都是一个具有单一目的的微小CSS属性。
实用类如何处理特异性
实用类不解决特异性,而是将BEM的低特异性理念发挥到极致。几乎所有实用类都具有(0,1,0)的最低特异性级别。
实用类的权衡
- 使代码看起来"丑陋"
- 存在重复问题
- 全局更改困难
- 破坏了自然的父子关系
层叠层:通过设计处理特异性
BEM提供结构,实用类获得速度,而CSS层叠层给了我们最重要的东西:控制。
|
|
由于@layer
的工作方式,.button
会胜出,因为components层是最高优先级的,即使#button
具有更高的特异性。
层叠层的细微差别
- 特异性仍然是游戏的一部分
!important
在@layer
中的行为与预期不同(它们反向工作!)@layers
不是选择器特定的,而是样式属性特定的@layer
容易被滥用
三者比较
特性 | BEM | 实用类 | 层叠层 |
---|---|---|---|
核心理念 | 命名空间组件 | 单一目的类 | 控制层叠顺序 |
特异性控制 | 低且平坦 | 完全避免 | 由于层优先级而绝对控制 |
代码可读性 | 命名清晰的结构 | 如果不熟悉类名则不清晰 | 如果遵循层结构则清晰 |
HTML冗长度 | 中等长度类名(可能变长) | 许多小类累加 | 无直接影响,仅存在于CSS中 |
最佳用例 | 设计系统 | 快速构建 | 需要覆盖的遗留代码或第三方代码 |
结论
在比较BEM、实用类和CSS层叠层时,是否有一种真正的"获胜"方法来控制层叠中的特异性?
首先,CSS层叠层可以说是多年来我们获得的最强大的CSS功能。它们不应该与BEM或实用类混淆,后者是策略而不是CSS功能集的一部分。
这就是为什么我喜欢将BEM与层叠层结合,或者将实用类与层叠层结合的想法。无论哪种方式,理念都是保持低特异性,并利用层叠层为这些样式设置优先级。