写过前端的都踩过这个坑——CSS 想读 HTML 里的 data 属性,以前只能靠 JS 先去读再写到 CSS 变量里,attr() 在 content 以外全是摆设。今天 Firefox 155 把这件事彻底原生化了

写过前端的都踩过这个坑——CSS 想读 HTML 里的 data 属性,以前只能靠 JS 先去读再写到 CSS 变量里,attr() 在 content 以外全是摆设。今天 Firefox 155 把这件事彻底原生化了。

这个坑踩得有多深?

以前你想让一个元素的宽度由 HTML 属性直接决定,得这么写:

document.querySelectorAll(".meter").forEach(el => {
const pct = el.dataset.pct;
el.style.setProperty("--pct", pct + "%");
});

.meter { width: var(--pct); }

五年前是这样,三年前还是这样,现在你打开 MDN 查 attr(),Chrome 133 就支持了,Firefox 155 刚发布,Safari 还在路上。但 90% 的前端项目里,这套 JS 桥接代码还在线上跑着。

## 现在的写法:attr() 直接出类型值

Firefox 155 稳定版把 CSS Values and Units Level 5 的 attr() 类型推导落地了,核心就是两个新语法:

**单位后缀速写:**

.card { width: attr(data-width px); }
.progress { height: attr(data-pct %); }
.rotate { transform: rotate(attr(data-deg deg)); }

**type() 显式声明 + 回退值:**

.meter { width: attr(data-pct type(), 60%); }
.badge { background: attr(data-color type(), #eee); }
.icon { font-size: attr(data-size rem, 1rem); }

Firefox 155 之前,这个写法在 Chrome 里写是能用的,但 Firefox 一直是实验性功能,需要手动开 layout.css.attr.enabled。从今天起,写完不用开任何 flag,线上直接用。

## 三类典型场景,JS 全部省掉

**进度条**——最常见的需求:

<div class="meter" data-pct="75"></div>

.meter { width: attr(data-pct type(), 0%); }

属性值直接驱动视觉,进度改了只要改 HTML,不用动一行 JS。

**动态主题色**——以前靠 CSS 变量桥接:

<div class="chip" data-tone="#f43f5e" data-radius="8px"></div>

.chip {
background: attr(data-tone type(), #eee);
border-radius: attr(data-radius type(), 4px);
}

单个 data 属性驱动多个 CSS 属性,属性一改样式全变。

**带 type() 的 if() 条件样式**——这个组合让 CSS 真正能做状态机:

.box {
background: if(attr(data-state) == loading, gold,
if(attr(data-state) == error, tomato,
steelblue));
}

以前这种逻辑只能写 class + JS 切换,现在纯 CSS 就能跑。

## 为什么这套方案比 CSS 变量更好

这里有个微妙的问题:既然 @property + CSS 变量也能做类型推导,attr() 的价值在哪?

attr() 的核心优势:HTML 本身就是数据源,不需要额外部署 CSS 变量同步机制。对于服务端渲染、静态生成、多人协作场景,让设计师直接在 HTML 里配置值,比维护一套 CSS 变量命名约定要直观得多。

## 渐进增强写法

Firefox 155 + Chrome 133 + Safari 15.4 以下的浏览器不支持 type() 语法,但回退值让降级天然安全:

.meter { width: 60%; }
@supports (width: attr(data-pct type())) {
.meter { width: attr(data-pct type(), 60%); }
}

不支持的浏览器走第一条,支持的浏览器走第二条,两个世界的行为都是合理的。

## 接下来怎么做

Firefox 155 已经稳定,下一步看看你项目里那些 element.style.setProperty("--xxx", value) 的代码,有多少是可以直接用 attr() 替代的。进度条、主题配置、动态尺寸——这三个场景优先级最高。

下次写组件需要动态样式,先问自己一句:能不能直接写在 HTML 属性里?

评论区

0 条评论

登录后可评论。

阿柯·前端架构 12 阅读