Skip to content

Css选择器

CSS 选择器是 CSS 的核心,它决定了样式规则会应用到哪些 HTML 元素上。而优先级(Specificity)则决定了当多个规则“打架”时,谁会胜出。

1. 常见 CSS 选择器

我们可以把选择器分为几个梯队:

1.1 基础选择器

  • 标签选择器 (Element Selector): 直接选中标签名。
css
/*(选中所有 <p>)*/
p { color: red; }
  • 类选择器 (Class Selector): 最常用的选择器,以 . 开头。
css
/*(选中所有 class="highlight")*/
.highlight { background: yellow; }
  • ID 选择器: 具有唯一性,以 # 开头。
css
/*(选中 id="navbar")*/
#navbar { height: 50px; }
  • 通配符选择器: 选中所有元素。
css
* { margin: 0; }
选择器示例描述
通配符选择器*选中页面上所有元素。
标签选择器div选中指定标签名的所有元素(如所有 <div>)。
类选择器.class选中 class 属性包含指定值的所有元素。
ID 选择器#id选中 id 属性为指定值的唯一元素。

1.2 组合选择器

  • 后代选择器 (空格): 选中某个元素内部的所有特定后代(包括子、孙子...)。
css
/*(选中 .card 内部的所有 p)*/
.card p {}
  • 子选择器 (>): 只选中直接子元素(儿子)。
css
/* (选中 .list 的直接 li 子元素)*/
.list > li {}
  • 并集选择器 (,): 同时选中多个。
css
/* (选中 h1,h2,.title多个元素)*/
h1, h2, .title {}
选择器示例描述
后代选择器div p选中 div 内部的所有 p(子、孙...)。
子选择器div > p选中 div 的直接子元素 p(仅儿子)。
相邻兄弟选择器div + p选中紧接在 div 之后的第一个 p。
通用兄弟选择器div ~ p选中 div 之后的所有同级 p。
并集选择器div, p同时选中 div 和 p(分组)。

1.3 属性选择器

根据元素的属性来选择。

css
/*(选中 type 为 text 的 input)*/
input[type="text"] {}
css
/*(选中 href 以 https 开头的链接)*/
a[href^="https"] {  }
选择器示例描述
[attr][target]选中带有 target 属性 的元素。
[attr=value][type="text"]选中属性值 完全等于指定值 的元素。
[attr~=value][title~="flower"]选中属性值 包含指定单词(空格分隔 的元素。
[attr^=value][href^="https"]选中属性值以指定字符串 开头 的元素。
[attr$=value][src$=".png"]选中属性值以指定字符串 结尾 的元素。
[attr*=value][class*="icon"]选中属性值 包含指定子字符串 的元素。

1.4 伪类选择器 (Pseudo-classes)

伪类用于选择元素的特定状态。它们以单冒号 (😃 开头。

  • 交互与状态伪类 (User Action & State)
伪类描述
:hover鼠标悬停时。
:active元素被激活时(通常指鼠标按下的瞬间)。
:focus元素获得焦点时(如点击输入框)。
:focus-visible现代浏览器特性,仅在通过键盘导航获得焦点时显示轮廓(提升无障碍体验)。
:focus-within当元素自身或其内部任何子元素获得焦点时。
:visited链接已被访问过。
:link链接尚未被访问。
:targetURL 的锚点指向当前元素时(如 URL 为 #section1 时选中 id="section1" 的元素)。
  • 结构性伪类 (Structural)
伪类描述
:root文档的根元素(通常是 <html>),优先级高于 html 标签选择器。
:empty没有子元素(包括文本节点)的元素。
:first-child父元素的第一个子元素。
:last-child父元素的最后一个子元素。
:only-child父元素中唯一的子元素。
:nth-child(n)父元素的第 n 个子元素(不区分类型)。支持 odd (奇数), even (偶数), 2n+1 等公式。
:nth-last-child(n)倒数第 n 个子元素。
:first-of-type同类型中的第一个兄弟元素。
:last-of-type同类型中的最后一个兄弟元素。
:only-of-type同类型中唯一的兄弟元素。
:nth-of-type(n)同类型中的第 n 个兄弟元素。
  • 表单相关伪类 (Form)
伪类描述
:checked被选中的 radio 或 checkbox。
:disabled被禁用的表单元素。
:enabled启用的表单元素。
:required带有 required 属性的 input。
:optional没有 required 属性的 input。
:valid / :invalid内容验证通过 / 不通过的 input。
:read-only只读的 input。
:read-write可读写的 input。
:placeholder-shown当 input 显示占位符(即内容为空)时。
:default默认选中的表单元素(如默认按钮)。
  • 逻辑组合伪类 (Functional / Logical) - 现代 CSS 重点
伪类描述
:not(selector)否定伪类。选中不匹配参数选择器的元素。
:is(selector, ...)匹配伪类。选中匹配参数列表中任意一个的元素。权重取决于参数中最高的那个。
:where(selector, ...)与 :is() 相同,但权重始终为 0(非常适合重置样式库)。
:has(selector)父级选择器!如果元素包含匹配参数的后代,则选中该父元素。(例如 div:has(img) 选中包含图片的 div)。

1.5 伪元素选择器 (Pseudo-elements)

选中元素的一部分,或者创建虚拟元素。通常用双冒号 ::。

伪元素描述
::before在元素内容之前插入生成的内容(需配合 content 属性)。
::after在元素内容之后插入生成的内容。
::first-letter选中块级元素第一行的第一个字母。
::first-line选中块级元素的第一行。
::selection选中用户鼠标框选(高亮)的文本部分。
::placeholder选中 input 的占位符文本样式。

2. 优先级 (Specificity) 计算规则 🔥

当同一个元素被多个选择器选中,且设置了相同的属性(比如都设置了 color),浏览器通过计算权重来决定听谁的。

我们将权重分为四个等级(A, B, C, D),通常表示为 (0, 0, 0, 0)。

2.1 权重等级表

等级选择器类型权重值 (示例)
特殊!important无限大 (最高优先级,无视一切)
A (千位)内联样式 (style="...")(1, 0, 0, 0)
B (百位)ID 选择器 (#id)(0, 1, 0, 0)
C (十位)类、伪类、属性(0, 0, 1, 0)
D (个位)标签、伪元素(0, 0, 0, 1)
0通配符 *、结合符 (+, >, ~)(0, 0, 0, 0) (无权重)

注意::not()伪类本身不增加权重,权重的增加取决于括号里面的选择器。

2.2 计算示例

让我们来做几道数学题:

等级选择器类型权重值
h1一个标签(0, 0, 0, 1)
.title类标签(0, 0, 1, 0)
#nav .list li1个 ID (#nav) + 1个类 (.list) + 1个标签 (li)(0, 1, 1, 1)
html body #nav .list li1个 ID + 1个类 + 3个标签(0, 1, 1, 3)
.card .title2个类(0, 0, 2, 0)
div#app1个 ID + 1个标签(0, 1, 0, 1)

2.3 关键规则总结

  • 越具体,优先级越高: ID > 类 > 标签。

  • 权重叠加: 多个选择器组合时,权重相加(但在同一等级内比较,低等级永远无法超越高等级,例如 100 个类也比不上 1 个 ID)。

  • 后来居上: 如果权重完全相同,后面写的规则会覆盖前面写的。

  • !important核武器: 加上 !important 的属性会覆盖所有其他规则(除了另一个 !important)。慎用! 除非你是在覆盖第三方库的样式且无法通过增加权重解决。

3. 实战建议

  • 尽量少用 ID 选择器写样式: ID 权重太高,复用性差,以后想覆盖它很难。推荐主要用 Class 类选择器。

  • 不要层级嵌套太深: .header .nav .list .item a { ... } 这种写法权重计算复杂且性能稍差。建议用 BEM 命名法(如 .nav__link)来保持扁平。

  • 避免使用 !important: 它是维护的噩梦。只有在通过正常权重无法解决问题时(例如覆盖内联样式)才考虑使用。