CSS 特定性详解

Avatar of Chris Coyier
Chris Coyier 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 价值 200 美元的免费积分!

让我们专门讨论这个主题。(敲击声!)

解释它的最佳方式是从特定性变得混乱且可能不像预期那样运行的示例开始。然后我们将仔细研究如何计算实际的特定性值以确定哪个选择器具有优先权。

这是一个简单的无序列表

<ul id="summer-drinks">
   <li>Whiskey and Ginger Ale</li>
   <li>Wheat Beer</li>
   <li>Mint Julip</li>
</ul>

现在您想指定其中一种为您的最爱饮料并更改其样式。您需要一个挂钩来执行此操作,因此您通过列表元素上的类名来应用它。

<ul id="summer-drinks">
   <li class="favorite">Whiskey and Ginger Ale</li>
   <li>Wheat Beer</li>
   <li>Mint Julip</li>
</ul>

现在您打开 CSS 并对新类进行样式化

.favorite {
  color: red;
  font-weight: bold;
}

然后您查看自己的作品,但是,它没有起作用! 您最喜欢的饮料的文本没有变成红色或变粗! 这里有些奇怪的事情在发生。

在 CSS 中进一步探查,您会发现这一点

ul#summer-drinks li {
   font-weight: normal;
   font-size: 12px;
   color: black;
}

这就是您的问题所在。两个不同的 CSS 选择器告诉该文本的颜色和字体粗细。只有一个字体大小语句,因此很明显,该语句将生效。这些不一定是“冲突”,但浏览器确实需要决定这些语句中的哪一个应该被认可。它是通过遵循一组标准的特定性规则来实现的。

我认为这会让一些初学者感到困惑,因为他们还没有完全弄清楚这一点。他们可能会认为,因为 .favorite 语句“在 CSS 中更靠下”,或者因为类=”favorite”在 HTML 中“更靠近实际文本”,它将是“获胜者”。

事实上,CSS 中选择器的顺序确实起作用,“更靠下”的选择器在特定性值完全相同的情况下确实会获胜。例如

.favorite {
   color: red;
}
.favorite {
   color: black;
}

颜色将是黑色…… 但我扯远了。

这里的重点是,您应该尽可能地使用特定性。即使使用上面提供的简单示例,您最终也会明白,仅仅使用类名来定位该“最爱饮料”是不够的,或者即使它起作用,也不安全。使用以下方法会更明智

ul#summer-drinks li.favorite {
  color: red;
  font-weight: bold;
}

这就是我所说的“尽可能地使用特定性”。您实际上可以更具体,并使用以下方法

html body div#pagewrap ul#summer-drinks li.favorite {
  color: red;
  font-weight: bold;
}

但这有点过分。它会使您的 CSS 难以阅读,而且没有实际的好处。另一种增强“.favorite”类的特定性值的方法是使用!important 声明。

.favorite {
  color: red !important;
  font-weight: bold !important;
}

我曾经听说,!important 就像 CSS 中的绝地心灵控制术。确实如此,您可以通过使用它来强制您的意志覆盖元素的样式。但!important 通过大幅提高特定选择器属性的特定性来施加这种意志。

如果误解了!important 声明,很容易被误用。最好使用它来保持 CSS 的整洁,在您知道具有特定类选择器的元素应该使用特定样式集无论如何的示例中。反之,不要将其用作快速解决方法来覆盖某些东西的样式,而是要弄清楚原始作者是如何构建和使用 CSS 的。

我经常使用的经典示例之一是

.last {
   margin-right: 0 !important;
}

我经常在有多个浮动块的情况下使用它,用于一行中的最后一个右侧块。这确保最后一个块没有任何右外边距,这会阻止它紧贴其父元素的右侧边缘。这些块中的每一个可能都有更具体的 CSS 选择器来应用右外边距,但!important 会突破这一点,并通过一个简单/干净的类来处理它。

计算 CSS 特定性值

为什么我们第一次尝试更改颜色和字体粗细失败了?正如我们所知,这是因为仅仅使用类名本身具有较低的特定性值,并且被另一个选择器(它针对具有 ID 值的无序列表)所取代。这句话中重要的词是ID。CSS 对类和 ID 应用了截然不同的特定性权重。事实上,ID 的特定性值无限高! 也就是说,没有任何数量的类本身可以超过 ID。

让我们来看看这些数字是如何计算的

换句话说

  • 如果元素具有内联样式,则该样式将自动1 获胜(1,0,0,0 分)
  • 对于每个 ID 值,应用 0,1,0,0 分
  • 对于每个类值(或伪类或属性选择器),应用 0,0,1,0 分
  • 对于每个元素引用,应用 0,0,0,1 分

您通常可以将这些值视为一个数字,例如 1,0,0,0 是“1000”,因此显然胜过 0,1,0,0 或“100”的特定性。逗号是为了提醒我们这并不是一个真正的“十进制”系统,因为您实际上可以有像 0,1,13,4 这样的特定性值——而且这个“13”不会像十进制系统那样溢出。

示例计算



更新::not() 类伪类本身不添加任何特定性,只有括号内的内容会添加到特定性值。



重要说明

  • 通配符选择器 (*) 没有特定性值 (0,0,0,0)
  • 伪元素 (例如 :first-line) 获得 0,0,0,1,不像它们的伪类兄弟获得 0,0,1,0
  • 伪类 :not() 本身不添加任何特定性,只有它括号内的内容会添加特定性。
  • 附加到 CSS 属性值的!important 值是自动获胜。它甚至会覆盖标记中的内联样式。唯一可以覆盖!important 值的方法是在 CSS 中稍后声明的另一个!important 规则,且具有相同或更大的特定性值,否则就会被覆盖。您可以将其视为在特定性值中添加 1,0,0,0,0。

资源