伪元素选择器

学习

伪元素选择器

2026-02-23/0/ 编辑


伪元素选择器

概述

伪元素选择器(Pseudo-element Selectors)用于选择元素的特定部分,例如首字母、首行、前面或后面的内容等。伪元素以双冒号 :: 开头。

语法

选择器::伪元素 {
  属性: 值;
}

注意: 单冒号 : 是旧语法,双冒号 :: 是新语法(推荐)。为了兼容性,浏览器通常两种语法都支持。

常用伪元素

1. ::before - 元素前面插入内容

在元素内容之前插入生成的内容。

.box::before {
  content: "前缀: ";
  color: red;
  font-weight: bold;
}
<div class="box">这是一段文字</div>
<!-- 实际显示: 前缀: 这是一段文字 -->

2. ::after - 元素后面插入内容

在元素内容之后插入生成的内容。

.box::after {
  content: " (后缀)";
  color: blue;
}
<div class="box">这是一段文字</div>
<!-- 实际显示: 这是一段文字 (后缀) -->

重要: ::before::after 必须设置 content 属性,否则不会显示。

3. ::first-letter - 首字母

选择块级元素的第一个字母。

p::first-letter {
  font-size: 3em;
  font-weight: bold;
  color: #e74c3c;
  float: left;
  margin-right: 5px;
}
<p>这是一段文字,首字母会被放大。</p>

4. ::first-line - 首行

选择块级元素的第一行。

p::first-line {
  font-weight: bold;
  color: #3498db;
  text-transform: uppercase;
}

5. ::selection - 选中的文本

选择用户选中的文本。

::selection {
  background-color: #3498db;
  color: white;
}

注意: 只能设置有限的属性:

  • color
  • background-color
  • cursor
  • outline
  • text-decoration
  • text-shadow

6. ::placeholder - 占位符文本

选择输入框的占位符文本。

input::placeholder {
  color: #999;
  font-style: italic;
}
<input type="text" placeholder="请输入用户名">

7. ::marker - 列表标记

选择列表项的标记(如圆点、数字等)。

li::marker {
  color: #3498db;
  font-size: 1.2em;
}

ul ::marker {
  content: "• ";
}

ol ::marker {
  content: counter(list-item) ". ";
  font-weight: bold;
}

8. ::backdrop - 背景遮罩

选择模态框等全屏元素背后的背景。

dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
}
<dialog open>
  <p>这是一个模态框</p>
</dialog>

权重计算

伪元素选择器的权重为 1:

p::first-letter {
  /* 权重 = 1(p) + 1(::first-letter) = 2 */
  font-size: 2em;
}

.box::before {
  /* 权重 = 10(.box) + 1(::before) = 11 */
  content: "★";
}

.container .item::after {
  /* 权重 = 10(.container) + 10(.item) + 1(::after) = 21 */
  content: "•";
}

常见应用场景

1. 清除浮动

.clearfix::after {
  content: "";
  display: block;
  clear: both;
}

2. 装饰性图标

.link::before {
  content: "→";
  margin-right: 5px;
  color: #3498db;
}

.download::after {
  content: "⬇";
  margin-left: 5px;
}
<a href="#" class="link">查看详情</a>
<a href="#" class="download">下载文件</a>

3. 卡片标签

.card::before {
  content: "NEW";
  position: absolute;
  top: 0;
  right: 0;
  background: #e74c3c;
  color: white;
  padding: 5px 10px;
  font-size: 12px;
  border-radius: 0 10px 0 10px;
}
<div class="card" style="position: relative;">
  <h3>产品标题</h3>
  <p>产品描述</p>
</div>

4. 引用样式

blockquote::before {
  content: """;
  font-size: 4em;
  color: #ddd;
  position: absolute;
  top: -20px;
  left: 0;
}

blockquote::after {
  content: """;
  font-size: 4em;
  color: #ddd;
  position: absolute;
  bottom: -40px;
  right: 0;
}

blockquote {
  position: relative;
  padding: 20px;
  background: #f9f9f9;
  border-left: 4px solid #3498db;
}

5. 分隔线

.separator::after {
  content: "";
  display: block;
  width: 100%;
  height: 1px;
  background: #eee;
  margin: 20px 0;
}

6. 工具提示

.tooltip {
  position: relative;
}

.tooltip::before {
  content: attr(data-tooltip);
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  background: #333;
  color: white;
  padding: 5px 10px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.tooltip:hover::before {
  opacity: 1;
}
<span class="tooltip" data-tooltip="这是一个提示信息">悬停查看提示</span>

7. 加载动画

.loader::after {
  content: "";
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 2px solid #3498db;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

8. 渐变边框

.gradient-border {
  position: relative;
  background: white;
  z-index: 1;
}

.gradient-border::before {
  content: "";
  position: absolute;
  top: -3px;
  left: -3px;
  right: -3px;
  bottom: -3px;
  background: linear-gradient(45deg, #3498db, #e74c3c, #f39c12);
  z-index: -1;
  border-radius: 5px;
}

9. 文字阴影效果

.text-shadow::after {
  content: attr(data-text);
  position: absolute;
  left: 2px;
  top: 2px;
  color: rgba(0,0,0,0.3);
  z-index: -1;
}

.text-shadow {
  position: relative;
}
<div class="text-shadow" data-text="文字阴影">文字阴影</div>

10. 图片遮罩

.image-overlay {
  position: relative;
  overflow: hidden;
}

.image-overlay::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.image-overlay:hover::after {
  opacity: 1;
}

实战案例

案例1: 自定义复选框

/* 隐藏原复选框 */
input[type="checkbox"] {
  display: none;
}

/* 自定义复选框 */
input[type="checkbox"] + label {
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 2px solid #ccc;
  border-radius: 4px;
  cursor: pointer;
  position: relative;
}

/* 选中状态 */
input[type="checkbox"]:checked + label {
  background-color: #3498db;
  border-color: #3498db;
}

/* 选中图标 */
input[type="checkbox"]:checked + label::after {
  content: "✓";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: white;
  font-size: 14px;
}

案例2: 新闻卡片

.news-card {
  position: relative;
  padding: 20px;
  background: white;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

/* 分类标签 */
.news-card::before {
  content: attr(data-category);
  position: absolute;
  top: 20px;
  right: 20px;
  background: #3498db;
  color: white;
  padding: 5px 10px;
  border-radius: 4px;
  font-size: 12px;
}

/* 分隔线 */
.news-card::after {
  content: "";
  display: block;
  width: 60px;
  height: 3px;
  background: #3498db;
  margin: 15px 0;
}
<div class="news-card" data-category="科技">
  <h3>新闻标题</h3>
  <p>新闻内容...</p>
</div>

案例3: 价格标签

.price-tag {
  position: relative;
  display: inline-block;
  padding: 10px 20px;
  background: #f39c12;
  color: white;
  border-radius: 5px;
}

/* 角标 */
.price-tag::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  border-width: 0 15px 15px 0;
  border-style: solid;
  border-color: #fff transparent #e67e22 transparent;
}

.price-tag::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  border-width: 15px 15px 0 0;
  border-style: solid;
  border-color: #e67e22 transparent transparent transparent;
}

案例4: 导航菜单

.nav-item {
  position: relative;
  padding: 10px 20px;
  cursor: pointer;
}

/* 悬停下划线 */
.nav-item::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 0;
  height: 2px;
  background: #3498db;
  transition: width 0.3s ease;
}

.nav-item:hover::after {
  width: 100%;
}

案例5: 按钮样式

.btn {
  position: relative;
  padding: 12px 30px;
  background: #3498db;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  overflow: hidden;
}

/* 悬停效果 */
.btn::before {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
  transition: left 0.5s ease;
}

.btn:hover::before {
  left: 100%;
}

/* 点击效果 */
.btn:active {
  transform: scale(0.98);
}

案例6: 评论系统

.comment {
  position: relative;
  padding: 20px;
  background: #f9f9f9;
  border-radius: 10px;
  margin-bottom: 20px;
}

/* 评论箭头 */
.comment::before {
  content: "";
  position: absolute;
  top: 20px;
  left: -10px;
  border-width: 10px 10px 10px 0;
  border-style: solid;
  border-color: transparent #f9f9f9 transparent transparent;
}

/* 用户头像 */
.comment::after {
  content: attr(data-avatar);
  position: absolute;
  top: 20px;
  left: -50px;
  width: 40px;
  height: 40px;
  background: #3498db;
  border-radius: 50%;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
}
<div class="comment" data-avatar="李">
  <h4>李明</h4>
  <p>这是一条评论内容。</p>
</div>

案例7: 时间轴

.timeline-item {
  position: relative;
  padding-left: 40px;
  margin-bottom: 30px;
}

/* 时间点 */
.timeline-item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  background: #3498db;
  border-radius: 50%;
  border: 4px solid white;
  box-shadow: 0 0 0 2px #3498db;
}

/* 时间线 */
.timeline-item::after {
  content: "";
  position: absolute;
  left: 9px;
  top: 20px;
  bottom: -30px;
  width: 2px;
  background: #ddd;
}

.timeline-item:last-child::after {
  display: none;
}

案例8: 标签页

.tab-content {
  display: none;
}

.tab-content:target {
  display: block;
  animation: fadeIn 0.3s ease;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
<a href="#tab1">标签1</a>
<a href="#tab2">标签2</a>
<a href="#tab3">标签3</a>

<div id="tab1" class="tab-content">内容1</div>
<div id="tab2" class="tab-content">内容2</div>
<div id="tab3" class="tab-content">内容3</div>

注意事项

  1. content 属性: ::before::after 必须设置 content 属性
  2. 只能设置一个: 每个选择器只能使用一个伪元素
  3. 不可选中: 伪元素生成的内容不能被用户选择
  4. 有限属性: 某些伪元素(如 ::selection)只能设置有限属性
  5. 性能考虑: 过多的伪元素可能影响性能
  6. 兼容性: 某些伪元素在旧浏览器中不支持

伪元素与伪类的区别

特性伪元素伪类
符号双冒号 ::单冒号 :
选择内容元素的特定部分元素的状态
示例::before, ::after:hover, :focus
数量每个元素最多两个可以多个
权重110

最佳实践

  1. content 属性: 使用 ::before::after 时必须设置
  2. 语义化: 不要用伪元素添加重要内容(搜索引擎无法索引)
  3. 性能优化: 避免过度使用伪元素
  4. 渐进增强: 为不支持伪元素的浏览器提供回退
  5. 代码注释: 复杂伪元素添加注释说明
  6. 可访问性: 考虑屏幕阅读器等辅助技术
  7. 动画效果: 合理使用伪元素实现动画效果
  8. 装饰用途: 主要用于装饰,避免用于核心内容

总结

伪元素选择器是 CSS 中强大的功能,能够为元素添加装饰性内容、选择特定部分。掌握各种伪元素的使用方法,可以帮助我们创建更丰富的视觉效果,减少 HTML 的复杂度。在实际开发中,要合理使用伪元素,确保代码的可维护性和性能。