在 CSS 的世界里,::before 和 ::after 是两位“隐形画家”,而 content 属性就是它们手中的画笔。借助 content,你可以在不触碰 HTML 结构的前提下,为页面添加图标、编号、提示文本、引号甚至图像。它看似简单,却隐藏着许多高级技巧。本文将带你系统掌握 content 的所有用法,并附上可直接上手的代码示例,让你的样式表更加优雅和强大。
一、重新认识 content
1.1 它属于谁?
content 属性 只能 与 ::before 和 ::after 伪元素一起使用(理论上可作用于普通元素,但所有现代浏览器均不支持)。其作用是在元素内部的前后位置插入“生成内容”,这些内容不会出现在 DOM 树中,仅用于视觉呈现。
元素::before {
content: "插入的内容";
}1.2 为什么需要它?
减少冗余标签:无需为了加一个图标或分隔线而添加空 <span>。
动态内容:可读取属性值或计数器,实现自动编号。
增强可维护性:将装饰性内容与 HTML 结构分离。
二、基础用法全解
2.1 直接插入字符串
最直观的用法,支持转义序列(如 \A 表示换行):
.important::before {
content: "⚠️ 注意:";
color: #d9534f;
}
/* 换行示例 */
.multiline::after {
content: "\A更多内容";
white-space: pre; /* 必须保留空白符 */
}技巧:使用 white-space: pre; 或 pre-wrap; 可以让 \A 生效。
2.2 引用属性值 attr()
动态获取元素的某个属性值作为内容,最常用于显示链接地址或自定义数据。
/* 显示链接地址 */
a[href]::after {
content: " (" attr(href) ")";
font-size: 0.8em;
color: #6c757d;
}/* 结合 data-* 属性 */
.tooltip-icon::after {
content: attr(data-hint);
/* 样式省略... */
}attr() 的限制:
只能返回 字符串,不能返回颜色、长度等数值(CSS 未来规范可能支持)。
如果属性不存在,会返回空字符串,不会报错。
2.3 插入图像 url()
.icon-external::after {
content: url("external-link.svg");
margin-left: 4px;
}缺点:无法控制图像的宽高(原尺寸显示),也不支持 background-size。 推荐替代方案:使用背景图 + 空内容装饰。
/* 更好的做法 */
.icon-decor::before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
background: url("icon.png") no-repeat center / contain;
margin-right: 4px;
}2.4 插入引号 open-quote / close-quote
配合 quotes 属性,可以实现自适应不同语言的引号风格:
q {
quotes: "“" "”" "‘" "’"; /* 外层双引号,内层单引号 */
}
q::before {
content: open-quote;
}
q::after {
content: close-quote;
}<p>鲁迅说:<q>世上本没有路,<q>走的人多了</q>也便成了路</q></p>
<!-- 输出:鲁迅说:“世上本没有路,‘走的人多了’也便成了路” -->2.5 空内容与纯装饰
最常见的是配合 display、width、height 等属性绘制图形或分割线:
.divider::before {
content: "";
display: block;
height: 1px;
background: linear-gradient(to right, #ccc, transparent);
margin: 20px 0;
}2.6 none 与 normal
两者效果相同,均不生成内容。常用于条件覆盖:
.no-content::before {
content: none;
}三、进阶功能:计数器(核心亮点)
计数器是 content 最强大的功能之一,可以实现自动编号、多级目录,甚至替代 <ol> 的复杂样式。
3.1 基础计数器
需要三个属性配合:
counter-reset:初始化计数器(通常放在父容器)。
counter-increment:递增计数器(放在每个需要编号的子元素上)。
content: counter(name):显示当前值。
.section-container {
counter-reset: section; /* 初始化名为 section 的计数器 */
}
.section {
counter-increment: section; /* 每次递增 1 */
}
.section::before {
content: counter(section) ". ";
font-weight: bold;
}3.2 嵌套计数器(多级编号)
使用 counters() 函数可以显示完整的层级路径,例如 “1.1”、“1.2.1”。
ol {
counter-reset: item;
list-style: none;
}
li {
counter-increment: item;
}
li::before {
content: counters(item, ".") " ";
}<ol>
<li>项目 1
<ol><li>项目 1.1</li><li>项目 1.2</li></ol>
</li>
<li>项目 2</li>
</ol>输出:
1 项目 1
1.1 项目 1.1
1.2 项目 1.2
2 项目 23.3 自定义编号格式
counter() 的第二个参数可以指定列表样式(如 upper-roman、lower-alpha):
.chapter::before {
content: counter(chapter, upper-roman) ". ";
}四、高级实战技巧
4.1 结合 CSS 自定义属性(变量)
:root {
--icon-success: "✓";
--icon-error: "✗";
}
.message.success::before {
content: var(--icon-success);
color: #28a745;
}
.message.error::before {
content: var(--icon-error);
color: #dc3545;
}4.2 响应式内容切换
根据屏幕宽度显示不同文字,减少 JavaScript 干预:
.nav-label::before {
content: "菜单";
}
@media (min-width: 768px) {
.nav-label::before {
content: "导航菜单";
}
}4.3 纯 CSS 提示框(Tooltip)
利用 attr() + 伪元素 + 悬停状态,实现简洁的提示效果:
<button data-tip="保存成功">提交</button>[data-tip] {
position: relative;
}
[data-tip]::after {
content: attr(data-tip);
position: absolute;
bottom: 120%;
left: 50%;
transform: translateX(-50%);
background: #212529;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.75rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
z-index: 1;
}
[data-tip]:hover::after {
opacity: 1;
}4.4 文章章节自动编号
为 h2、h3 自动生成“1 标题”、“1.1 子标题”:
body {
counter-reset: h2;
}
h2 {
counter-reset: h3;
counter-increment: h2;
}
h2::before {
content: counter(h2) " ";
color: #007bff;
}
h3 {
counter-increment: h3;
}
h3::before {
content: counter(h2) "." counter(h3) " ";
}4.5 打印时显示链接地址
提升打印文档的可读性:
@media print {
a[href]::after {
content: " <" attr(href) ">";
text-decoration: none;
color: #000;
}
}4.6 面包屑导航分隔符
.breadcrumb li {
display: inline;
}
.breadcrumb li + li::before {
content: "/";
margin: 0 8px;
color: #6c757d;
}五、常见误区与注意事项
误区 | 正确理解 |
|---|---|
可以在普通元素上用 content | ❌ 只有 ::before / ::after 支持 |
生成的内容会被屏幕阅读器朗读 | ❌ 辅助技术通常会忽略,重要信息必须放在 HTML 中 |
url() 插入的图像可以控制尺寸 | ❌ 原尺寸显示,推荐改用 background-image |
attr() 可以返回颜色、长度 | ❌ 目前只能返回字符串 |
计数器必须配合 <ol> 使用 | ❌ 可以用于任何元素,实现任意自动编号 |
可访问性提示:
永远不要依赖 content 来传递关键信息(如表单验证错误、操作指引)。对于装饰性内容则无妨。
性能提示:
大量使用 counter 或复杂选择器可能会轻微影响渲染性能,但在正常页面中几乎可以忽略。url() 插入多张图片会增加 HTTP 请求,建议合并或使用图标字体。
六、浏览器兼容性
截至 2026.05.02

Chrome、Firefox、Safari、Edge:全功能支持。
IE 8+:基础支持(attr() 仅字符串,计数器部分支持;url() 支持)。
IE 7 及以下:不支持。
现代项目中可以放心使用,但若需支持 IE 8,注意 counters() 可能存在问题。
总结
content 属性是 CSS 伪元素的灵魂,它用极小的代价实现了动态内容插入、自动编号、属性读取等强大功能。掌握它,你可以:
彻底告别为了装饰而添加的空标签。
轻松实现多级目录、面包屑、自定义列表标记。
创建响应式文本提示和优雅的打印样式。
结合 CSS 变量和数据属性,让样式更加灵活。
但也要牢记:content 生成的只是视觉层的“幻影”,无法替代真实的 HTML 内容,尤其要关注可访问性。在合适的场景下使用它,你的代码会变得更简洁、更语义化。
现在,不妨打开你的项目,尝试用 content 替换掉那些繁琐的装饰性 span 或 i 标签,体验一下“无中生有”的快感吧!
彩蛋
文中配有完整示例,点击《CSS content 属性 · 现代化深色模式完整演示》即可查看。
