Skip to content

03|CSS 选择器与优先级

HTML 搭好骨架后,需要 CSS 来控制外观。CSS 的核心问题是:选谁,然后改成什么样。选择器负责"选谁",声明块负责"改成什么样"。这篇先把选择器讲清楚——选不对元素,后面的样式声明再正确也落不到目标上。

一、基础选择器

元素选择器

直接写标签名,选中页面中所有该标签:

css
p {
  color: #333;
}

h1 {
  font-size: 24px;
}

上面的规则让所有 p 标签文字变深灰,所有 h1 标签字号 24 像素。元素选择器覆盖面太广,通常和其他选择器配合使用。

类选择器

. 开头,选中带有对应 class 属性的元素。这是日常开发最常用的选择器:

html
<p class="intro">这是介绍文字。</p>
<p>这是普通段落。</p>
css
.intro {
  color: #666;
  font-style: italic;
}

只有带有 class="intro" 的段落会应用 italic 样式。一个元素可以有多个类,用空格分隔:

html
<div class="card highlight">...</div>
css
.card {
  border: 1px solid #ddd;
  padding: 16px;
}

.highlight {
  background-color: #fffbe6;
}

这个 div 同时具有卡片边框和高亮背景。类的命名用小写、连字符分隔(article-title,不是 articleTitlearticle_title),这是 CSS 社区的普遍约定。

ID 选择器

# 开头,选中带有对应 id 属性的元素:

html
<div id="header">...</div>
css
#header {
  background-color: #f5f5f5;
}

同一页面中,id 必须唯一。CSS 层面不强制唯一(重复 id 时选择器仍能匹配),但 JavaScript 的 getElementById 只会返回第一个,且 id 作为页面锚点使用时也必须唯一。ID 选择器的优先级很高,过度使用会导致后续样式难以覆盖。

通用选择器

* 选中所有元素,通常用于重置默认样式:

css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

通用选择器的优先级最低,会被任何其他选择器覆盖。

二、组合选择器

后代选择器

用空格分隔,选中某元素内部的所有目标元素(无论嵌套多深):

css
.article p {
  line-height: 1.8;
}

选中所有位于 .article 元素内部的 p 标签,不管中间隔了多少层。

子代选择器

> 分隔,只选中直接子元素:

css
.nav > li {
  display: inline-block;
}

只选中 .nav 的直接 li 子元素。如果 li 内部还有嵌套的 li,不会被选中。

相邻兄弟选择器

+ 分隔,选中紧接在指定元素之后的第一个兄弟元素:

css
h2 + p {
  margin-top: 0;
}

选中紧跟在 h2 后面的第一个 p。如果 h2p 之间有其他元素,则不生效。

通用兄弟选择器

~ 分隔,选中指定元素之后的所有兄弟元素:

css
h2 ~ p {
  color: #666;
}

选中 h2 之后所有同级的 p,不要求紧邻。

三、伪类

伪类选中元素的特定状态或位置,以 : 开头:

状态伪类

css
/* 鼠标悬停 */
a:hover {
  text-decoration: underline;
}

/* 获得焦点(键盘 Tab 或点击输入框) */
input:focus {
  border-color: #1890ff;
  outline: none;
}

/* 已访问的链接 */
a:visited {
  color: #800080;
}

位置伪类

css
/* 第一个子元素 */
li:first-child {
  border-top: none;
}

/* 最后一个子元素 */
li:last-child {
  border-bottom: none;
}

/* 第 n 个子元素 */
li:nth-child(2) {
  background-color: #f0f0f0;
}

/* 奇数项 */
li:nth-child(odd) {
  background-color: #fafafa;
}

/* 偶数项 */
li:nth-child(even) {
  background-color: #fff;
}

nth-child 的参数可以是数字、关键字(odd/even)或公式(2n+1 表示奇数项,3n 表示每三项)。

否定伪类

css
/* 选中不是 .disabled 的按钮 */
button:not(.disabled) {
  cursor: pointer;
}

四、伪元素

伪元素创建不存在于 HTML 中的元素,以 :: 开头:

css
/* 在元素内容前插入 */
.quote::before {
  content: """;
  color: #999;
}

/* 在元素内容后插入 */
.quote::after {
  content: """;
  color: #999;
}

/* 第一行 */
p::first-line {
  font-weight: bold;
}

/* 选中的文字 */
::selection {
  background-color: #1890ff;
  color: #fff;
}

::before::after 必须配合 content 属性使用,即使 content 为空字符串。插入的内容在 DOM 中不可见,不属于 HTML 结构,但会渲染在页面上。

CSS2 中伪元素用一个冒号(:before),CSS3 规范改为双冒号(::before)以区分伪类。现代浏览器两者都支持,但推荐使用双冒号写法。

五、优先级(特指度)

当多个选择器对同一个元素声明了冲突的样式时,浏览器按优先级决定应用哪一条。优先级由三个数字组成 (a, b, c)

分量计数规则
aID 选择器的数量
b类选择器、伪类、属性选择器的数量
c元素选择器、伪元素的数量

比较时先比 aa 相同再比 bb 相同再比 c

css
/* (0, 0, 1) - 一个元素 */
p { color: black; }

/* (0, 1, 0) - 一个类 */
.text { color: red; }

/* (0, 1, 1) - 一个类 + 一个元素 */
p.text { color: blue; }

/* (1, 0, 0) - 一个 ID */
#intro { color: green; }

对同一个段落 <p class="text" id="intro">,最终颜色是绿色——ID 选择器的优先级最高。

内联样式

写在元素 style 属性中的样式优先级高于所有选择器:

html
<p style="color: purple;">这段文字是紫色</p>

内联样式的特指度记为 (1, 0, 0, 0),比 ID 选择器的 (1, 0, 0) 更高。

!important

css
p {
  color: red !important;
}

!important 覆盖一切优先级计算,包括内联样式。除非处理第三方库的样式覆盖,否则不要使用 !important。一旦滥用,样式追踪会变得极其困难。

优先级相同的情况

如果两个选择器的特指度完全相同,后写的规则生效

css
.text { color: red; }
.text { color: blue; }  /* 这条生效,段落为蓝色 */

六、继承

部分 CSS 属性会自动从父元素继承到子元素:

可继承属性不可继承属性
colorwidthheight
font-familyfont-sizemarginpadding
line-heightborderbackground
text-aligndisplayposition
css
body {
  color: #333;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

页面中所有文字都会继承 body 的字体和颜色,不需要给每个元素重复声明。不可继承的属性(如 margin)需要显式设置。

可以用 inherit 关键字强制继承:

css
input {
  font-family: inherit;  /* 强制继承父元素的字体 */
}

七、常见错误

过度使用 ID 选择器

css
/* 不建议:ID 优先级过高,后续难以覆盖 */
#sidebar .menu .item a { color: #333; }

/* 建议:用类控制,保持优先级扁平 */
.sidebar-menu-link { color: #333; }

选择器过长

css
/* 不建议:维护困难,性能差 */
.page-wrapper .content-area .article-list .article-item .title {
  font-size: 18px;
}

/* 建议:给目标元素直接加类 */
.article-title { font-size: 18px; }

选择器越长,浏览器匹配时的工作量越大,且一旦 HTML 结构变动(中间某层 div 改名或增加),CSS 就会失效。

用 !important 解决优先级问题

css
/* 错误:引入 important 后,后续所有覆盖都需要 important */
.button { color: red !important; }

/* 正确:提升原选择器的优先级 */
.button.primary { color: blue; }