CSS Handbook · 伪元素

第三章 / 3.1 ::before 与 ::after

第三章 · 3.1 节

::before 与 ::after


这两个伪元素会在被选中元素的内容前后各"生成"一个虚拟子元素,让我们无需修改 HTML 结构,就能用纯 CSS 添加装饰性内容。它们是伪元素家族中使用频率最高的一对。

content 属性

没有 content 属性,::before / ::after 就不会被渲染——哪怕只是空字符串,也必须显式声明。

.required::after {
  content: " *";
  color: #b3452c;
}
效果预览
邮箱 *

content 除了字符串,还能引用属性值或图片:

a[href]::after {
  content: " (" attr(href) ")";
}
.icon::before {
  content: url(icon.svg);
}

装饰性图形

因为伪元素本质是一个可定位、可设置尺寸的盒子,配合 position 与 border,可以画出许多不需要额外图片的图形。

.card { position: relative; }
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 4px; height: 100%;
  background: #8a5a2e;
}
效果预览:左侧装饰条
卡片内容

实战:纯 CSS 提示气泡

借助 ::after 生成气泡本体,再用 ::before 生成一个旋转 45° 的小三角作为箭头:

.tip { position: relative; }
.tip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: #26233a;
  color: #fff;
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s;
}
.tip:hover::after { opacity: 1; }

配合计数器使用

counter-reset / counter-increment 与 content: counter(name) 联手,可以实现自动编号,且能跨越多级列表:

ol { counter-reset: step; list-style: none; }
ol li { counter-increment: step; }
ol li::before {
  content: counter(step) ".";
  color: #8a5a2e;
  margin-right: 6px;
}

常见误区

  • ::before / ::after 对 img、input 等替换元素不生效,因为它们没有可插入内容的"内部"。
  • 生成的内容默认是 inline,需要时应显式设置 display。
  • 伪元素内容不会被屏幕阅读器之外的辅助技术很好地支持,重要信息不应仅依赖伪元素呈现。

Chapter 3 · Section 3.1

::before and ::after


These two pseudo-elements each "generate" a virtual child element before and after the content of the selected element, letting us add decorative content with pure CSS without modifying the HTML structure. They are the most frequently used pair in the pseudo-element family.

The content Property

Without the content property, ::before / ::after will not be rendered — even an empty string must be declared explicitly.

.required::after {
  content: " *";
  color: #b3452c;
}
Preview
Email *

Besides strings, content can also reference attribute values or images:

a[href]::after {
  content: " (" attr(href) ")";
}
.icon::before {
  content: url(icon.svg);
}

Decorative Shapes

Because a pseudo-element is essentially a box that can be positioned and sized, combining position and border lets you draw many shapes that need no extra images.

.card { position: relative; }
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 4px; height: 100%;
  background: #8a5a2e;
}
Preview: left accent bar
Card content

In Practice: A Pure-CSS Tooltip Bubble

Use ::after to generate the bubble itself, and ::before for a small triangle rotated 45° as the arrow:

.tip { position: relative; }
.tip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: #26233a;
  color: #fff;
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s;
}
.tip:hover::after { opacity: 1; }

Working with Counters

counter-reset / counter-increment together with content: counter(name) enable automatic numbering that can span multiple levels of lists:

ol { counter-reset: step; list-style: none; }
ol li { counter-increment: step; }
ol li::before {
  content: counter(step) ".";
  color: #8a5a2e;
  margin-right: 6px;
}

Common Pitfalls

  • ::before / ::after do not work on replaced elements such as img and input, because they have no "inside" into which content can be inserted.
  • Generated content is inline by default; set display explicitly when needed.
  • Pseudo-element content is not well supported by assistive technologies beyond screen readers, so important information should not rely solely on pseudo-elements.