原来:列名在表头(thead)中
现在:用伪元素在每个 td 前面动态生成列名。啥意思?不明白
一、用最通俗的例子解释
想象你有一张Excel表格,现在要在手机上显示:
原始表格(宽屏)
text
┌──────┬────────────┬────────┐ │ 姓名 │ 年龄 │ 城市 │ ← 这是表头(列名) ├──────┼────────────┼────────┤ │ 张三 │ 25 │ 北京 │ ← 这是数据行 │ 李四 │ 30 │ 上海 │ └──────┴────────────┴────────┘
手机屏幕太小,不能横着放
普通做法(直接缩小):字太小看不清
聪明做法(转换布局):把每一行变成一张"卡片"
二、转换过程详解
第1步:看原始 HTML 结构
html
<!-- 表头(thead) --><thead> <tr> <th>姓名</th> <!-- 列名1 --> <th>年龄</th> <!-- 列名2 --> <th>城市</th> <!-- 列名3 --> </tr></thead><!-- 数据行(tbody) --><tbody> <tr> <td>张三</td> <!-- 数据1 --> <td>25</td> <!-- 数据2 --> <td>北京</td> <!-- 数据3 --> </tr> <tr> <td>李四</td> <td>30</td> <td>上海</td> </tr></tbody>
问题:数据单元格 <td> 不知道自己是哪一列,只知道自己是第1个、第2个、第3个。
第2步:在手机上,我们希望看到什么?
text
┌─────────────┐ │ 姓名:张三 │ ← 第1行第1列数据,带上"姓名"标签 │ 年龄:25 │ ← 第1行第2列数据,带上"年龄"标签 │ 城市:北京 │ ← 第1行第3列数据,带上"城市"标签 └─────────────┘ ┌─────────────┐ │ 姓名:李四 │ │ 年龄:30 │ │ 城市:上海 │ └─────────────┘
关键问题:每个 <td>25</td> 这个单元格,怎么知道它前面应该显示"年龄"这两个字?
第3步:CSS 伪元素的解决方案
核心思想:用 CSS 的 :before 伪元素,在每个 <td> 的前面插入文字。
css
td:before {
content: "年龄"; /* 固定写死,不灵活 */}但这样所有 <td> 前面都显示"年龄",不对!
第4步:用 data-title 属性解决
在 HTML 中给每个 td 添加自定义属性:
html
<tbody> <tr> <td data-title="姓名">张三</td> <!-- 告诉 CSS:前面显示"姓名" --> <td data-title="年龄">25</td> <!-- 告诉 CSS:前面显示"年龄" --> <td data-title="城市">北京</td> <!-- 告诉 CSS:前面显示"城市" --> </tr> <tr> <td data-title="姓名">李四</td> <td data-title="年龄">30</td> <td data-title="城市">上海</td> </tr></tbody>
CSS 动态读取这个属性:
css
td:before {
content: attr(data-title); /* 读取 data-title 属性的值 */}工作原理:
第一个
<td>的data-title="姓名"→ 伪元素显示"姓名"第二个
<td>的data-title="年龄"→ 伪元素显示"年龄"第三个
<td>的data-title="城市"→ 伪元素显示"城市"
三、用 Chrome 开发者工具看效果
在浏览器中,实际"看到"的 DOM 结构是这样的:
html
<!-- 你写的 HTML --><td data-title="姓名">张三</td><!-- 浏览器渲染时,CSS 插入伪元素后,视觉效果相当于 --><td data-title="姓名"> <before>姓名</before> <!-- 伪元素,不在 DOM 中,但能看到 --> 张三</td>
画图示意:
text
┌─────────────────────────┐ │ 你写的 HTML: │ │ <td data-title="姓名">张三</td> │ ├─────────────────────────┤ │ 浏览器实际显示: │ │ ┌──────┬────────────┐ │ │ │ 姓名 │ 张三 │ │ │ └──────┴────────────┘ │ │ ↑ │ │ └─ 伪元素插入的内容 │ └─────────────────────────┘
四、完整代码示例(可以直接运行)
html
<!DOCTYPE html><html><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>伪元素示例</title>
<style>
/* 基础样式 */
.card {
border: 1px solid #ccc;
margin: 10px;
padding: 10px;
}
/* 关键:用伪元素显示标签 */
.card-item {
margin: 5px 0;
}
.card-item:before {
content: attr(data-label); /* 读取 data-label 属性 */
font-weight: bold;
display: inline-block;
width: 80px;
}
</style></head><body>
<h2>学生信息(卡片式布局)</h2>
<!-- 第1张卡片 -->
<div class="card">
<div class="card-item" data-label="姓名">张三</div>
<div class="card-item" data-label="年龄">25岁</div>
<div class="card-item" data-label="城市">北京</div>
</div>
<!-- 第2张卡片 -->
<div class="card">
<div class="card-item" data-label="姓名">李四</div>
<div class="card-item" data-label="年龄">30岁</div>
<div class="card-item" data-label="城市">上海</div>
</div></body></html>运行效果:
text
学生信息(卡片式布局) ┌─────────────────┐ │ 姓名:张三 │ │ 年龄:25岁 │ │ 城市:北京 │ └─────────────────┘ ┌─────────────────┐ │ 姓名:李四 │ │ 年龄:30岁 │ │ 城市:上海 │ └─────────────────┘
五、回到你的代码
你的代码中:
css
td:before {
content: attr(data-title); }这句话的意思是:
"在每个
<td>元素的内容之前,插入一个伪元素,这个伪元素显示的内容来自当前<td>的data-title属性"
但你的 HTML 中并没有 data-title 属性,所以不会显示任何标签!
正确的 HTML 应该是:
html
<!-- 原来 --><td>1</td><!-- 应该改成 --><td data-title="序号">1</td>
六、为什么这样设计?
| 特点 | 说明 |
|---|---|
| 语义化 | data-title 是自定义属性,不影响 HTML 结构 |
| 动态性 | 可以用 JavaScript 自动从 thead 读取并添加 |
| 纯 CSS | 不需要额外的 JavaScript 来生成标签 |
| 可访问性 | 屏幕阅读器可以读到伪元素的内容 |
七、总结
| 概念 | 解释 |
|---|---|
| 表头(thead) | 原本在表格顶部,显示"姓名、年龄、城市" |
| 数据单元格(td) | 原本只显示"张三、25、北京" |
| 伪元素(:before) | CSS 虚拟元素,可以在 td 前面插入内容 |
| attr(data-title) | 读取 HTML 属性的值作为伪元素的内容 |
| 最终效果 | 每个 td 显示为"列名:值"的格式 |
一句话总结:
伪元素就像一个"贴纸",CSS 通过
attr(data-title)读取每个单元格上的标签信息,然后把这个贴纸贴在单元格前面,这样就实现了"从表头拿列名"的效果。
记忆口诀:
"表头太远够不着,data-title 身上贴;伪元素当搬运工,attr 读取前面放"