伪类与伪元素
:nth-child、:not、:is、::before、::after
前置知识
建议先阅读以下内容再进入本文:
伪元素
基本写法:::before 前置内容
<选择器>::before { content: <内容>; }
/* 添加前置图标 */
.link::before {
content: "→ ";
}
基本写法:::after 后置内容
<选择器>::after { content: <内容>; }
/* 添加后置内容 */
.required::after {
content: " *";
color: red;
}
基本写法:::first-letter 首字母
<选择器>::first-letter { }
/* 段落首字母放大 */
p::first-letter {
font-size: 2em;
float: left;
}
基本写法:::first-line 首行
<选择器>::first-line { }
/* 段落首行样式 */
p::first-line {
font-weight: bold;
}
基本写法:::selection 选中文本
::selection { }
/* 选中文本样式 */
::selection {
background: #3498db;
color: white;
}
基本写法:::placeholder 占位符
input::placeholder { }
/* 占位符文本样式 */
input::placeholder {
color: #999;
}
基本写法:::marker 列表标记
li::marker { }
/* 列表项标记样式 */
li::marker {
color: #3498db;
font-weight: bold;
}
基本写法:::file-selector-button 文件按钮
input[type=file]::file-selector-button { }
/* 文件选择按钮样式 */
input[type=file]::file-selector-button {
background: #3498db;
color: white;
border: none;
padding: 6px 12px;
}
结构伪类
基本写法::first-child 第一个子元素
<选择器>:first-child { }
/* 第一个列表项样式 */
li:first-child {
font-weight: bold;
}
基本写法::last-child 最后一个子元素
<选择器>:last-child { }
/* 最后一个列表项样式 */
li:last-child {
border-bottom: none;
}
基本写法::only-child 唯一子元素
<选择器>:only-child { }
/* 父元素唯一子元素样式 */
.icon:only-child {
margin: 0 auto;
}
基本写法::first-of-type 同类型首个
<选择器>:first-of-type { }
/* 第一个段落样式 */
p:first-of-type {
font-size: 1.2em;
}
基本写法::last-of-type 同类型末个
<选择器>:last-of-type { }
/* 最后一个段落样式 */
p:last-of-type {
margin-bottom: 0;
}
基本写法::nth-child 第 N 个子元素
<选择器>:nth-child(<n>) { }
/* 第 2 个子元素 */
li:nth-child(2) {
color: red;
}
基本写法::nth-child 奇偶
<选择器>:nth-child(odd | even) { }
/* 隔行变色 */
tr:nth-child(even) {
background: #f9f9f9;
}
基本写法::nth-child 公式
<选择器>:nth-child(<公式>) { }
/* 每 3 个元素选第 1 个 */
li:nth-child(3n+1) {
color: blue;
}
基本写法::nth-last-child 倒数第 N 个
<选择器>:nth-last-child(<n>) { }
/* 倒数第 2 个子元素 */
li:nth-last-child(2) {
color: green;
}
基本写法::nth-of-type 同类型第 N 个
<选择器>:nth-of-type(<n>) { }
/* 第 2 个段落 */
p:nth-of-type(2) {
color: red;
}
基本写法::empty 空元素
<选择器>:empty { }
/* 空段落隐藏 */
p:empty {
display: none;
}
基本写法::root 根元素
:root { }
/* 定义全局 CSS 变量 */
:root {
--primary: #3498db;
}
1. 伪类概述
伪类用于匹配元素的特定状态。
| 类别 | 示例 | 说明 |
|---|---|---|
| 交互状态 | :hover, :focus, :active | 用户交互 |
| 位置 | :first-child, :nth-child() | DOM 位置 |
| 输入状态 | :checked, :disabled | 表单状态 |
| 否定 | :not() | 排除匹配 |
| 匹配 | :is(), :where(), :has() | 复杂匹配 |
2. :nth-child()
li:nth-child(3) {
color: red;
} /* 第 3 个 */
tr:nth-child(odd) {
background: #f0f0f0;
} /* 奇数 */
li:nth-child(3n + 1) {
color: blue;
} /* 每 3 个选第 1 个 */
li:nth-child(-n + 3) {
font-weight: bold;
} /* 前 3 个 */
An+B 语法:2n+1 = odd,2n = even,-n+3 = 前3个
nth-child vs nth-of-type
<div>
<h1>标题</h1>
<!-- h1:first-of-type -->
<p>段落1</p>
<!-- p:nth-of-type(1) -->
<p>段落2</p>
<!-- p:nth-of-type(2) -->
</div>
3. 否定与匹配伪类
li:not(:last-child) {
border-bottom: 1px solid #ccc;
}
:is(h1, h2, h3):hover {
color: blue;
}
:where(h1, h2, h3) {
margin: 0;
} /* 优先级为 0 */
a:has(> img) {
border: none;
}
4. 交互伪类
a:hover {
color: blue;
}
input:focus-visible {
box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.3);
}
input:focus-within {
border-color: blue;
}
button:active {
transform: scale(0.98);
}
5. 伪元素
.quote::before {
content: '\201C';
font-size: 2em;
}
.clearfix::after {
content: '';
display: table;
clear: both;
}
p::first-line {
font-weight: bold;
}
p::first-letter {
font-size: 3em;
float: left;
}
::selection {
background: #ff6b6b;
color: white;
}
input::placeholder {
color: #999;
}
链接与交互伪类
基本写法::link 未访问链接
a:link { }
/* 未访问链接样式 */
a:link {
color: blue;
}
基本写法::visited 已访问链接
a:visited { }
/* 已访问链接样式 */
a:visited {
color: purple;
}
基本写法::hover 悬停
<选择器>:hover { }
/* 鼠标悬停样式 */
.button:hover {
background: #2980b9;
}
基本写法::active 激活
<选择器>:active { }
/* 鼠标按下样式 */
.button:active {
transform: scale(0.95);
}
基本写法::focus 获得焦点
<选择器>:focus { }
/* 获得焦点样式 */
input:focus {
border-color: #3498db;
outline: none;
}
基本写法::focus-visible 键盘焦点
<选择器>:focus-visible { }
/* 仅键盘聚焦时显示焦点框 */
input:focus-visible {
outline: 2px solid #3498db;
}
基本写法::focus-within 子元素聚焦
<选择器>:focus-within { }
/* 子元素获得焦点时父元素样式 */
.form:focus-within {
border-color: #3498db;
}
表单伪类
基本写法::checked 选中状态
input:checked { }
/* 复选框选中样式 */
input:checked + label {
color: #27ae60;
}
基本写法::disabled 禁用
input:disabled { }
/* 禁用输入框样式 */
input:disabled {
background: #f0f0f0;
cursor: not-allowed;
}
基本写法::enabled 可用
input:enabled { }
/* 可用输入框样式 */
input:enabled {
background: white;
}
基本写法::required 必填
input:required { }
/* 必填字段样式 */
input:required {
border-left: 3px solid #e74c3c;
}
基本写法::valid 有效
input:valid { }
/* 校验通过样式 */
input:valid {
border-color: #27ae60;
}
基本写法::invalid 无效
input:invalid { }
/* 校验失败样式 */
input:invalid {
border-color: #e74c3c;
}
基本写法::placeholder-shown 占位显示
input:placeholder-shown { }
/* 输入框为空显示占位符时 */
input:placeholder-shown {
background: #fafafa;
}
基本写法::read-only 只读
input:read-only { }
/* 只读输入框样式 */
input:read-only {
background: #f5f5f5;
}
否定与匹配伪类
基本写法::not 否定
<选择器>:not(<排除选择器>) { }
/* 非特殊按钮的样式 */
.button:not(.special) {
background: gray;
}
基本写法::not 多条件否定
<选择器>:not(<选择器1>, <选择器2>) { }
/* 排除多个选择器 */
input:not(:disabled, [type="hidden"]) {
border: 1px solid #ccc;
}
基本写法::is 匹配任一
<选择器>:is(<选择器1>, <选择器2>) { }
/* 匹配多个标题级别 */
:is(h1, h2, h3) {
color: #333;
}
基本写法::where 匹配任一(零优先级)
<选择器>:where(<选择器1>, <选择器2>) { }
/* 零优先级匹配便于覆盖 */
:where(.card) .title {
font-size: 1.2em;
}
状态伪类
基本写法::target 目标锚点
<选择器>:target { }
/* 锚点目标高亮 */
.section:target {
background: #fffacd;
}
基本写法::default 默认选项
input:default { }
/* 默认选中的单选按钮 */
input:default {
box-shadow: 0 0 0 2px #3498db;
}
基本写法::indeterminate 不确定状态
input:indeterminate { }
/* 不确定状态复选框 */
input:indeterminate {
background: gray;
}
现代 CSS 伪类(2024+)
基本写法::has 父级选择
<选择器>:has(<子选择器>) { }
/* 包含图片的卡片样式 */
.card:has(img) {
padding: 0;
}
基本写法::has 否定形式
<选择器>:not(:has(<子选择器>)) { }
/* 不包含错误的表单 */
.form:not(:has(.error)) {
border-color: #27ae60;
}
基本写法::has 多条件
<选择器>:has(<选择器1>, <选择器2>) { }
/* 包含图片或视频的容器 */
.container:has(img, video) {
aspect-ratio: 16 / 9;
}
基本写法::defined 自定义元素已定义
<选择器>:defined { }
/* 自定义元素定义后显示 */
custom-element:not(:defined) {
display: none;
}
基本写法::modal 模态框
<选择器>:modal { }
/* 原生模态框样式 */
dialog:modal {
border: none;
border-radius: 8px;
}
基本写法::fullscreen 全屏
<选择器>:fullscreen { }
/* 全屏元素样式 */
.video:fullscreen {
width: 100vw;
height: 100vh;
}
基本写法::picture-in-picture 画中画
<选择器>:picture-in-picture { }
/* 画中画视频样式 */
video:picture-in-picture {
border: 2px solid #3498db;
}
基本写法::playing 播放中
<选择器>:playing { }
/* 视频播放时样式 */
video:playing {
filter: brightness(1.1);
}
@scope 作用域(2024+)
基本写法:@scope 限定作用域
@scope (<选择器>) { <规则> }
/* 限定样式作用范围 */
@scope (.card) {
.title {
color: red;
}
}
基本写法:@scope 范围限定
@scope (<起>) to (<止>) { }
/* 限定到 .start 到 .end 之间 */
@scope (.start) to (.end) {
p {
color: blue;
}
}
交互状态伪类
基本写法:hover 悬停
<选择器>:hover { <样式> }
/* 鼠标悬停状态 */
.button:hover {
background-color: #0056b3;
}
基本写法:focus 聚焦
<选择器>:focus { <样式> }
/* 元素获得焦点 */
input:focus {
border-color: #007bff;
}
基本写法:focus-visible 键盘聚焦
<选择器>:focus-visible { <样式> }
/* 仅键盘聚焦时显示 */
button:focus-visible {
outline: 2px solid #007bff;
}
基本写法:focus-within 子元素聚焦
<选择器>:focus-within { <样式> }
/* 子元素获得焦点时 */
.form:focus-within {
border-color: #007bff;
}
基本写法:active 激活
<选择器>:active { <样式> }
/* 元素被激活(点击) */
.button:active {
transform: scale(0.95);
}
基本写法:visited 已访问
<选择器>:visited { <样式> }
/* 链接已访问状态 */
a:visited {
color: purple;
}
基本写法:link 未访问
<选择器>:link { <样式> }
/* 链接未访问状态 */
a:link {
color: blue;
}
表单状态伪类
基本写法:checked 选中
<选择器>:checked { <样式> }
/* 复选框或单选框选中 */
input:checked {
accent-color: #007bff;
}
基本写法:disabled 禁用
<选择器>:disabled { <样式> }
/* 表单元素禁用 */
input:disabled {
background-color: #f5f5f5;
cursor: not-allowed;
}
基本写法:enabled 可用
<选择器>:enabled { <样式> }
/* 表单元素可用 */
input:enabled {
background-color: white;
}
基本写法:required 必填
<选择器>:required { <样式> }
/* 必填字段 */
input:required {
border-color: red;
}
基本写法:optional 可选
<选择器>:optional { <样式> }
/* 可选字段 */
input:optional {
border-color: #ccc;
}
基本写法:valid 有效
<选择器>:valid { <样式> }
/* 表单验证通过 */
input:valid {
border-color: green;
}
基本写法:invalid 无效
<选择器>:invalid { <样式> }
/* 表单验证失败 */
input:invalid {
border-color: red;
}
基本写法:in-range 范围内
<选择器>:in-range { <样式> }
/* 数值在指定范围内 */
input:in-range {
border-color: green;
}
基本写法:out-of-range 范围外
<选择器>:out-of-range { <样式> }
/* 数值超出指定范围 */
input:out-of-range {
border-color: red;
}
基本写法:read-only 只读
<选择器>:read-only { <样式> }
/* 只读字段 */
input:read-only {
background-color: #f5f5f5;
}
基本写法:read-write 可读写
<选择器>:read-write { <样式> }
/* 可读写字段 */
input:read-write {
background-color: white;
}
基本写法:placeholder-shown 占位符显示
<选择器>:placeholder-shown { <样式> }
/* 显示占位符时 */
input:placeholder-shown {
border-color: #ccc;
}
基本写法:default 默认选中
<选择器>:default { <样式> }
/* 默认选中的表单元素 */
input:default {
box-shadow: 0 0 2px blue;
}
目标伪类
基本写法:target 锚点目标
<选择器>:target { <样式> }
/* 当前锚点指向的元素 */
#section:target {
background-color: #ffffcc;
}
语言伪类
基本写法:lang 语言匹配
<选择器>:lang(<语言>) { <样式> }
/* 匹配指定语言 */
p:lang(zh) {
font-family: "Microsoft YaHei", sans-serif;
}
否定伪类
基本写法:not 否定
<选择器>:not(<排除选择器>) { <样式> }
/* 排除指定选择器 */
input:not([disabled]) {
border: 1px solid #ccc;
}
基本写法:not 多重否定
<选择器>:not(<选择器1>):not(<选择器2>) { <样式> }
/* 多重否定 */
input:not([disabled]):not([type="hidden"]) {
border: 1px solid #ccc;
}
匹配伪类
基本写法:is 匹配任一
:is(<选择器1>, <选择器2>) { <样式> }
/* 匹配多个选择器 */
:is(h1, h2, h3) {
font-family: sans-serif;
}
基本写法:where 匹配任一
:where(<选择器1>, <选择器2>) { <样式> }
/* 匹配多个选择器(零特异性) */
:where(.card, .panel) {
padding: 1rem;
}
基本写法:has 父选择器
<选择器>:has(<子选择器>) { <样式> }
/* 选中包含指定子元素的父元素 */
div:has(img) {
padding: 10px;
}
基本写法:has 否定
<选择器>:not(:has(<子选择器>)) { <样式> }
/* 不包含指定子元素 */
div:not(:has(img)) {
background: #f5f5f5;
}
伪元素内容生成
基本写法:content 字符串
content: "<文本>";
/* 生成文本内容 */
.label::before {
content: "标签: ";
}
基本写法:content attr 属性
content: attr(<属性名>);
/* 生成元素属性值 */
a::after {
content: " (" attr(href) ")";
}
基本写法:content 空字符串
content: "";
/* 生成空内容用于布局 */
.clearfix::after {
content: "";
display: block;
clear: both;
}
基本写法:content url 图片
content: url("<图片路径>");
/* 生成图片内容 */
.icon::before {
content: url("icon.png");
}
基本写法:content 计数器
content: counter(<计数器名>);
/* 显示计数器值 */
li::before {
content: counter(item) ". ";
}
计数器
基本写法:counter-reset 重置计数器
counter-reset: <计数器名> <初始值>;
/* 重置计数器 */
ol {
counter-reset: section;
}
基本写法:counter-increment 递增计数器
counter-increment: <计数器名> <步长>;
/* 计数器递增 */
li {
counter-increment: section;
}
基本写法:counter 显示计数器
content: counter(<计数器名>);
/* 显示计数器值 */
li::before {
content: "第 " counter(section) " 章: ";
}
基本写法:counter 自定义样式
content: counter(<计数器名>, <样式>);
/* 计数器使用中文数字 */
li::before {
content: counter(section, cjk-ideographic) "、";
}
基本写法:counters 嵌套计数器
content: counters(<计数器名>, "<分隔符>");
/* 嵌套计数器 */
li::before {
content: counters(section, ".") " ";
}
伪元素动画
基本写法:伪元素过渡
<选择器>::before { transition: <属性> <时长>; }
/* 伪元素过渡动画 */
.button::before {
transition: transform 0.3s;
}
.button:hover::before {
transform: scaleX(1);
}
基本写法:伪元素动画
<选择器>::after { animation: <名称> <时长>; }
/* 伪元素动画 */
.loader::after {
animation: spin 1s linear infinite;
}
伪元素布局
基本写法:clearfix 清除浮动
.clearfix::after { content: ""; display: table; clear: both; }
/* 清除浮动 */
.clearfix::after {
content: "";
display: table;
clear: both;
}
基本写法:tooltip 工具提示
<选择器>::after { content: attr(data-tooltip); <样式> }
/* 使用伪元素创建工具提示 */
[data-tooltip]::after {
content: attr(data-tooltip);
position: absolute;
background: black;
color: white;
padding: 4px 8px;
opacity: 0;
transition: opacity 0.3s;
}
[data-tooltip]:hover::after {
opacity: 1;
}
基本写法:下划线动画
<选择器>::after { content: ""; <样式> }
/* 悬停下划线动画 */
.link::after {
content: "";
display: block;
width: 0;
height: 2px;
background: currentColor;
transition: width 0.3s;
}
.link:hover::after {
width: 100%;
}
本章综合挑战(选做)
- 用
:nth-child(odd)给表格做隔行变色; - 用
::before给必填项加红色星号; - 用
:focus-visible给键盘焦点加可见描边; - 用
:has()实现“含图片的卡片显示大图”; - 用计数器自动生成“第 1 节/第 2 节”标题编号。
核心知识点
一句话记住伪类/伪元素:单冒号看状态(hover、nth-child),双冒号造内容(before、after);
:not排除、:is合并、:has找父。
- 伪类匹配状态与位置:
:hover、:focus、:active、:nth-child、:checked; - 伪元素生成内容:
::before/::after必须有content; :nth-child(An+B)的语法:odd/even/-n+3;:nth-of-type与:nth-child的区别是“同类型 vs 所有兄弟”;:is()合并选择器,:where()合并且优先级为 0,:has()反向匹配父元素;- 现代增强:
:user-invalid、:focus-visible、@scope、计数器。
注意事项与改进建议
| 问题点 | 说明 | 改进方案 |
|---|---|---|
伪元素忘记 content | 不显示 | 至少写 content: '' |
:nth-child 与 :nth-of-type 混用 | 选中元素不符合预期 | 按“所有兄弟/同类型”区分 |
用 :hover 做移动端交互 | 触屏无悬停 | 用 :focus/媒体查询 |
大量 :has() 嵌套 | 匹配性能下降 | 简化选择器或改用类 |
移除 :focus 样式 | 键盘用户迷失 | 保留 :focus-visible 样式 |
:where 优先级困惑 | 覆盖失败 | 记住它优先级为 0 |
扩展学习
- 选择器总览:
css/130-CSS3SelectorSystem; - 优先级计算:
css/170-PriorityCalculation; - 表单状态:
css/360-MediaQuery之外的:user-invalid等交互增强; - 嵌套与作用域:
css/720-CSSNestingInPractice、css/710-ScopeAtRule; - 伪元素布局:
css/680-CSSProjectExampleResponsiveHomepage中的实际应用。