CSS Handbook · 选择器

第二章 / 2.2 组合选择器与优先级

第二章 · 2.2 节

组合选择器与优先级


把基础选择器按不同的连接符组合起来,就能精确描述元素之间的结构关系。理解这四种组合方式,再加上一套优先级计算规则,就能预判任何一条 CSS 规则最终会不会生效。

后代选择器(空格)

两个选择器之间以空格分隔,匹配前者内部任意深度的后代元素,不要求直接嵌套。

.article p {
  color: #5c5872;
}

无论 p 是 .article 的直接子元素,还是被包裹在多层 div 中,都会命中。

子代选择器(>)

只匹配直接子元素,不会穿透更深的层级,常用于避免样式意外污染嵌套组件。

.nav > li {
  display: inline-block;
}
实践建议在编写组件库样式时,优先使用子代选择器而非后代选择器,能有效避免样式"渗透"进组件内部嵌套的同名标签。

相邻兄弟选择器(+)

匹配紧跟在前一个元素之后、且拥有相同父元素的下一个兄弟节点。

h2 + p {
  margin-top: 0;
}
效果预览:紧邻标题的段落取消上边距
小标题
紧跟其后的段落,margin-top 被清零。

通用兄弟选择器(~)

匹配同一父元素下、在前一个元素之后出现的所有符合条件的兄弟节点,不要求紧邻。

.tab-radio:checked ~ .tab-panel {
  display: block;
}

这也是"纯 CSS 标签页 / 手风琴"技巧的核心原理:借助 :checked 状态与通用兄弟选择器联动,无需 JavaScript。

优先级计算

当多条规则同时命中同一元素的同一属性时,浏览器按"优先级"高低决定生效的声明。优先级由四个等级构成,从高到低依次为:

等级示例权重记法
内联样式style="color:red"1,0,0,0
ID 选择器#nav0,1,0,0
类 / 属性 / 伪类.btn / [type] / :hover0,0,1,0
标签 / 伪元素div / ::before0,0,0,1

逐级比较,高位相同再比下一位;!important 会越过以上所有等级,应当谨慎使用。例如 .nav .item.active 的权重是 0,0,2,0,高于 .item(0,0,1,0),但低于 #nav .active(0,1,1,0)。

.item { color: gray; }         /* 0,0,1,0 */
.nav .item.active { color: teal; } /* 0,0,2,0 —— 生效 */

层叠与来源顺序

当两条规则优先级完全相同时,"层叠"(Cascade)规则介入:后声明的规则覆盖先声明的规则。这也是为什么 CSS 文件的书写顺序、以及 <link> 标签的引入顺序会影响最终效果。现代 CSS 还引入了 @layer 层叠层,可以显式控制不同来源样式之间的覆盖关系,这里先作了解,留待进阶主题展开。

Chapter 2 · Section 2.2

Combinators and Specificity


Combining basic selectors with different combinators lets you describe structural relationships between elements precisely. Understand these four combinators, add a set of specificity calculation rules, and you can predict whether any CSS rule will actually take effect.

Descendant Combinator (space)

Two selectors separated by a space match a descendant element at any depth inside the former, without requiring direct nesting.

.article p {
  color: #5c5872;
}

Whether p is a direct child of .article or wrapped in several layers of div, it will match.

Child Combinator (>)

Matches only direct children and does not pierce deeper levels, often used to avoid styles accidentally leaking into nested components.

.nav > li {
  display: inline-block;
}
Practice tipWhen writing component library styles, prefer the child combinator over the descendant combinator to keep styles from "seeping" into same-named tags nested inside components.

Adjacent Sibling Combinator (+)

Matches the next sibling that immediately follows the previous element and shares the same parent.

h2 + p {
  margin-top: 0;
}
Live preview: the paragraph right after a heading loses its top margin
Subheading
The paragraph right after it, with margin-top reset to zero.

General Sibling Combinator (~)

Matches every eligible sibling that appears after the previous element under the same parent, without requiring adjacency.

.tab-radio:checked ~ .tab-panel {
  display: block;
}

This is also the core principle behind the "pure CSS tabs / accordion" trick: link states through :checked with the general sibling combinator — no JavaScript needed.

Calculating Specificity

When several rules hit the same property of the same element, the browser decides which declaration wins by "specificity". Specificity is made of four tiers, from highest to lowest:

TierExampleWeight notation
Inline stylesstyle="color:red"1,0,0,0
ID selectors#nav0,1,0,0
Class / attribute / pseudo-class.btn / [type] / :hover0,0,1,0
Type / pseudo-elementdiv / ::before0,0,0,1

Compare tier by tier, and only look at the next tier when the higher ones tie; !important vaults past all of these tiers and should be used with care. For example, .nav .item.active has a weight of 0,0,2,0, higher than .item (0,0,1,0) but lower than #nav .active (0,1,1,0).

.item { color: gray; }         /* 0,0,1,0 */
.nav .item.active { color: teal; } /* 0,0,2,0 — wins */

The Cascade and Source Order

When two rules have exactly the same specificity, the "cascade" kicks in: the rule declared later overrides the one declared earlier. This is why the order of declarations in a CSS file, and the order in which <link> tags are included, affect the final result. Modern CSS has also introduced @layer cascade layers, which let you explicitly control the override relationships between styles from different sources — we mention it here for awareness and leave the details for an advanced topic.