attr() 必须同时满足选择器绑定真实元素、元素含对应data-属性、伪元素声明content才生效;它仅返回字符串,不响应dataset变更,不可参与计算,无fallback,且伪元素内容不进入dom、不可选不可复制、无障碍阅读器通常忽略。

content: attr() 必须配合具体选择器和 data 属性才能生效
直接写 content: attr(data-label) 不会自动生效,它依赖三个硬性条件同时满足:选择器绑定了真实 DOM 元素、该元素上存在对应 data- 属性、伪元素声明了 content。漏掉任一环,结果都是空白,且无报错提示。
-
.tip::before { content: attr(data-tip); }正确 —— 有具体类名、有伪元素、有content -
div::before { content: attr(data-id); }危险 —— 若页面中任意<div> 没带 <code>data-id,那一处就显示空字符串,容易误判为失效 -
.box::before { content: attr(title); }无效 ——title是 HTML 全局属性,但attr()在大多数浏览器中只可靠读取data-开头的自定义属性 - 别指望用
width: calc(attr(data-count) * 10px)—— 语法错误,直接被忽略 - 别在 React/Vue 中靠修改
dataset驱动伪元素内容 —— 它不监听 property 变更 - 属性值为空或不存在时,
content就是空字符串,没有 fallback 机制(比如attr(data-label, "默认")是非法写法) - 用户无法选中、右键复制那段文字,哪怕它看起来和普通文本一模一样
- JS 查不到这个节点:
document.querySelector('.tip::before')是无效语法,getComputedStyle(el, '::before').content只能读值,不能操作 - 无障碍阅读器(screen reader)通常忽略伪元素内容,关键提示信息别放这儿
- 打印样式表里,伪元素默认不出现,需额外加
@media print { .tip::before { content: attr(data-tip); } }
attr() 返回的是字符串,不能参与 CSS 计算或响应 JS dataset 修改
attr(data-count) 拿到的是 "42",不是数字 42;el.dataset.count = "100" 不会触发伪元素更新,只有 el.setAttribute('data-count', '100') 才行。这意味着:
伪元素渲染后不可选、不可复制、不进 DOM 树
这是最容易被忽略的底层事实:::before 生成的内容只是 CSS 渲染层的一次性输出,浏览器不会把它挂到 DOM 树里。所以:











