关键要点
选择器特异性对于大多数中大型项目来说都是一个真正的问题,与任何其他经常重复出现的编码问题一样,它需要仔细处理。甚至 CSS-Tricks 最近也有一篇文章介绍如何保持 CSS 特异性较低。在你尝试使用 !important
之前,让我提醒你:> CSS/日常技巧:如果所有内容都是 !important
,则没有任何内容是 !important
。——Tony Nelson (@tonynelson19) 2010 年 11 月 18 日
CSS 特异性并不复杂,但社区已经做了很多工作来使其尽可能易于理解,通过使用与鱼和星球大战的类比或使用扑克术语来编写指南。在线有交互式计算器可用,甚至还有 Sass 的特异性 mixin,允许你检查并输出选择器的精确特异性值。在 CSS 特异性策略中,越简单越好,本文中的特异性解决方法(可能感觉有点笨拙)适用于架构不允许简单修复的情况。在决定哪种方法最适合你的项目时,请运用你的判断力,并最终尝试在干净且易于维护的 CSS 之间取得完美的平衡。
方法 0 – BEM
BEM 不仅仅是一种命名约定,它是由 Yandex 发明的前端工具包,其理念是更接近面向对象编程。在实践中,这意味着为你要设置样式的每一件事都使用类名。虽然“在层叠样式表中不进行层叠”对某些人来说可能听起来很荒谬,但在创建应该易于维护、可移植、自给自足、易于修改和可扩展的模块时,避免使用类型选择器和避免嵌套的想法非常有帮助。然而,BEM 方法的主要优点之一是它使每个选择器的特异性保持不变,因此几乎不会出现由过于具体的选择器引起的问题,这就是为什么这种方法是 0 号方法——如果你采用它,你实际上消除了项目中选择器特异性方面未来出现的任何问题。
由于你将只为编写的所有内容使用单个类,因此每个选择器的特异性都将为 0,1,0
有无数关于使用 BEM 的前端架构的成功案例,然而,尽管 BEM 非常流行,但它并不适用于特定类型的项目。它似乎非常适合前端开发人员是唯一编写 HTML 的项目。但是,如果你为内容编辑器至少编写部分内容的 CMS 编写内容,则 BEM 将受到严重限制。BEM 的纯形式不允许嵌套和类型选择器,例如 .Section--dark > a
(例如,使其具有浅色),而是要求你为锚点标签发明一个类。这导致了一个问题——内容编辑器将通过图形界面插入默认链接,这可能会导致链接几乎不可见。这也可能适用于特定部分中的所有段落、列表或图像。有时需要能够编写不带类的纯 HTML 内容,在这种情况下,解决方案是让父级使用后代选择器对其进行样式设置。这种级联的使用允许上下文灵活性——当某些内容位于不同的上下文中时,它会具有自定义样式。因此,我们需要一个实际的解决方案,用于我们无法使用纯 BEM 的情况,这种情况相当常见。CSS 预处理器可以在这里帮助我们,所有 3 个流行的预处理器——LESS、Sass 和 Stylus 都能够在我们需要使用更具体的选择器覆盖选择器时简化我们的工作。
方法 1 – 使用选择器添加前缀
当你遇到特异性问题并想要使某个选择器更重时,你可以在现有选择器前添加类、属性、ID 或类型选择器。通过这种方式,你可以稍微提高特异性。虽然此功能主要用于使用条件 html 标签定位 IE,但它还有更多有待开发的功能。CSS 预处理器中的父引用选择器 (&) 可以轻松地让我们添加选择器前缀以使其更重,因此我们可以执行以下操作:
<code>.class { body & { foo: bar; } }</code>
生成的 CSS:
<code>.class { body & { foo: bar; } }</code>
你可能希望使用 html 或 body 标签添加前缀,但你也可以使用页面上存在的一些更具体的内容,例如 .page
、#wrapper
、html[lang]
等。Sass 允许你在将来发生更改时将添加前缀的选择器放在变量中,此外,对于大型项目,可能值得创建一组具有不同权重的添加前缀的选择器:
<code>body .class { foo: bar; }</code>
这将生成:
<code>$prepend1: "html &"; $prepend2: "#wrapper &"; .selector { #{$prepend1} { background: #cacaca; } #{$prepend2} { background: #fefefe; } }</code>
其他流行的预处理器,如 LESS 和 Stylus 也提供此功能。
使用类型选择器为我们最初的类选择器 0,1,0 添加前缀将导致 0,1,1,使用 ID 添加前缀 – 1,1,0。这里的缺点是,一旦你使用代码中最重的选择器(即 #wrapper
)添加了某个选择器的前缀,你就无法再覆盖它,除非你发明一个新的、更重的选择器,而这并非总是可能的。
方法 2 – 自链选择器
添加选择器前缀很有用,但它不是无限可扩展的解决方案——你可能只有有限的方法来定位父级。此外,一旦你使用代码中最重的选项为多个选择器添加了前缀,你就会限制以后解决特异性问题的选项(特别是如果你使用了 ID)。前端社区最近被提醒了一个非常有用的 CSS 功能——自链选择器来提高其特异性。自链选择器适用于 ID、类和属性选择器,但不适用于类型选择器。但是,如果你主要使用类来设置内容样式,则自链选择器为你提供了一种无限可扩展的方式来覆盖任何选择器。借助父引用选择器,你可以轻松地将相同的选择器多次链接到自身(这适用于 ID、类和属性选择器,但不适用于类型选择器)。但是,你需要在第一个之后插入每个 &,最低要求是 Sass 3.4:
<code>html .selector { background: #cacaca; } #wrapper .selector { background: #fefefe; }</code>
<code>.selector { {&} { background: #cacaca; } {&}{&} { background: #fefefe; } }</code>
同样,你也可以使用 LESS 和 Stylus 执行此操作。如果这对你的口味来说太难看,你可以随时创建一个 mixin,它可以迭代地提高任何单个选择器的特异性。此 mixin 使用一些高级功能,也需要 Sass 3.4:
<code>.selector.selector { background: #cacaca; } .selector.selector.selector { background: #fefefe; }</code>
生成的 CSS:
<code>@mixin specificity($num: 1) { $selector: &; @if $num > 1 { @for $i from 1 to $num { $selector: $selector + &; } @at-root #{$selector} { @content; } } @else { @content; } } .selector { @include specificity(2) { background: #cacaca; } @include specificity(3) { background: #fefefe; } }</code>
你可以在 Stylus 中创建相同的 mixin,不幸的是,在 LESS 中没有简单的方法可以创建这样的 mixin。
自链将选择器的特异性从 0,1,0 提高到 0,2,0,再到 0,3,0,依此类推,使其几乎无限可扩展。
最终想法
在我们比以往任何时候都更智能的 CSS 中处理特异性问题的下一个自然步骤是创建一种方法来识别冲突的声明,使用 David Khourshid 的 Sass mixin 之类的东西计算每个实体的特异性,然后自动使用上述方法之一来提高特异性。也许我对自我感知样式表的梦想过于乐观,但我认为随着 CSS 预处理器的发展,我们代码中复杂的逻辑将会增加。下次你需要处理特异性问题时,你会使用上述哪种方法?你使用什么其他策略来解决你的特异性问题?
关于 CSS 预处理器和选择器特异性的常见问题
选择器特异性是 CSS 中的一个概念,它确定在存在冲突规则时将哪些样式应用于元素。它是一个分配给不同类型选择器(例如 ID、类和类型选择器)的权重系统。在 Sass 或 Less 等 CSS 预处理器中,此概念保持不变。但是,这些预处理器提供了额外的功能,例如嵌套,这会影响选择器的特异性。
嵌套是 CSS 预处理器中的一项功能,允许你编写更有条理且更易于阅读的代码。但是,它也会增加选择器的特异性。每个嵌套级别都会增加特异性,使嵌套选择器比父选择器更具体。这对于覆盖样式很有用,但如果管理不当,也可能导致意想不到的后果。
选择器的特异性是根据使用的选择器类型计算的。通常,ID 选择器的特异性最高,其次是类选择器,然后是类型选择器。每种类型的选择器都分配不同的权重,总特异性是这些权重的总和。一些 CSS 预处理器,如 Sass,提供用于计算选择器特异性的函数。
“&”符号用于 Sass 等 CSS 预处理器中,以引用嵌套规则中的父选择器。这对于创建更具体的选择器或将样式应用于元素的不同状态(如悬停或活动状态)很有用。
在 Sass 中,你可以通过复制选择器来提高其特异性。这被称为链接或双选择器。例如,.class.class
的特异性将高于 .class
。但是,应谨慎使用此方法,因为它会使你的 CSS 更难维护和覆盖。
高特异性会使你的 CSS 更难维护和覆盖。它可能导致所谓的特异性冲突,你必须不断提高选择器的特异性才能覆盖之前的样式。这会导致 CSS 膨胀和复杂。
有几种策略可以管理 CSS 预处理器中的特异性。一种是尽可能使用低特异性选择器。另一种是避免不必要的嵌套,因为这会增加特异性。你还可以使用 BEM(块、元素、修饰符)方法来保持特异性较低且一致。
是的,你可以使用 !important
规则来覆盖 CSS 预处理器中的特异性。但是,这应该作为最后手段,因为它会使你的 CSS 更难维护,并可能导致特异性冲突。
选择器的顺序会影响 CSS 预处理器中的特异性。如果两个选择器的特异性相同,则 CSS 中最后出现的选择器将被应用。这称为源顺序特异性。
是的,内联样式在 CSS 中具有最高的特异性,可以覆盖其他样式。但是,应谨慎使用它们,因为它们会使你的 CSS 更难维护,并可能导致样式不一致。
以上是CSS预处理器的选择器特异性的详细内容。更多信息请关注PHP中文网其他相关文章!