普通视图

发现新文章,点击刷新页面。
今天 — 2025年5月19日首页

原子化的未来?了解一下全面进化的CSS attr函数

作者 XboxYan
2025年5月19日 09:24

欢迎关注我的公众号:前端侦探

CSS attr函数相信大家都用过了吧,通常会配合伪元素content动态生成内容,比如一个简易的tooltip

<span class="css-tips" data-title="我是tooltip" >提示上</span>

通过attr动态生成

.css-tips[data-title]:after {
  content: attr(data-title);
  /*...*/
}

效果如下

image-20250516200454818

你可以访问这个链接查看完整demo: codepen.io/xboxyan/pen…

不过,之前仅仅支持字符串形式,对于数字、颜色等都无法识别,例如

<div w="10"></div>
<style>
  div{
    width: attr(w) /**不生效/
  }
</style>

现在,CSS attr迎来了全面进化(chrome 133+),很多问题都得到了很好的解决,一起看看吧~

一、快速上手

比如这样一个结构,是不是看着有些眼熟?

<div w="100" h="100"></div>
<style>
  div{
    background: royalblue;
  }
</style>

那么,如何让属性上的尺寸传递应用到实际的宽高上呢?你可以这样

[w]{
  width: attr(w px)
}
[h]{
  height: attr(h px)
}

来看看效果

image-20250516170508419

我们可以用之前的规则,将尺寸通过content显示出来

div:before{
  content: attr(w) '*' attr(h);
  color: white;
  font-size: 14px;
}

效果如下

image-20250516170636866

更为关键的是,这些完全是自动获取的,你可以设置多个任意尺寸

<div w="100" h="100"></div>
<div w="200" h="100"></div>
<div w="300" h="100"></div>

效果如下

image-20250516170814615

是不是非常灵活?

二、语法详解

现在来看看语法规则

attr(<attr-name> <attr-type>? , <fallback-value>?)

其实相比之前的规则,多了两个可选参数,一个是attr-type,表示属性类型,完整类型可以参考

developer.mozilla.org/en-US/docs/…

还有一个是allback-value,表示回退值,一些写法如下

/* Basic usage */
attr(data-count)
attr(href)

/* With type */
attr(data-width px)
attr(data-size rem)
attr(data-name raw-string)
attr(id type(<custom-ident>))
attr(data-count type(<number>))
attr(data-size type(<length> | <percentage>))

/* With fallback */
attr(data-count type(<number>), 0)
attr(data-width px, inherit)
attr(data-something, "default")

前面的例子其实带类型的值,除了使用px,还可以使用任何已有的CSS单位,比如

<div w="100" h="100" rotate="45"></div>

这里定义了一个旋转角度,可以直接加上角度单位deg

[rotate]{
  rotate: attr(rotate deg)
}

效果如下

image-20250516172610893

但是,有些值其实是不带单位的,比如颜色,并没有什么后缀单位,比如

<div w="100" h="100" rotate="45" bg="red"></div>

这时,可以采用type来手动指定

[bg]{
  background: attr(bg type(<color>));
}

效果如下

image-20250516181308281

有些属性可能不止一种类型,比如background,支持颜色,也支持渐变,还支持图像,这里其实也能定义多种类型

[bg]{
  background: attr(bg type(<color>|<image>));
}

我们换成渐变试试

<div w="100" h="100" rotate="45" bg="linear-gradient(orange,red)"></div>

也能完美适配

image-20250516182249509

多个值写起来可能比较麻烦,可以用通配符来代替,相当于传入什么,读取的就是什么

[bg]{
  background: attr(bg type(*));
}

最后就是回退值,非常类CSS变量,当属性不存在时(注意不能是空),采用回退值,比如

div{
  background: attr(bg type(*), royalblue);
}

现在去除bg属性

<div w="100" h="100" rotate="45"></div>

就回到了默认的宝蓝色

image-20250516183003948

你也可以访问在线demo真实体验: codepen.io/xboxyan/pen…

三、带数字显示的进度条

下面来看一个案例

image-20250516185648485

在过去,如果想用单个标签、单一变量来实现,通常会用到CSS变量,就像这样

<div class="progress" style="--value:30"></div>
<div class="progress" style="--value:42.5"></div>
<div class="progress" style="--value:50"></div>
<div class="progress" style="--value:90"></div>

进度很好办,直接用这个变量计算就好了,那后面的数字怎么办呢?直接使用变量是不行的

::before{
  content: var(--value) /*不生效*/
}

其实可以用计数器来实现,类似于这样

.progress::before {
  --value: 50;
    counter-reset: progress var(--value);
    content: counter(value);
}

有兴趣可以查看张老师的这篇文章: 小tips: 如何借助content属性显示CSS var变量值

不过计数器在正常场景下不支持小数,导致有些场景受限

如果需要展示小数可以参考这篇文章: 如何让CSS计数器支持小数的动态变化?

现在有了attr,可以直接用属性来实现,实现更方便

<div class="progress" value="30"></div>
<div class="progress" value="42.5"></div>
<div class="progress" value="50"></div>
<div class="progress" value="90"></div>

直接通过渐变绘制进度attr(value %)

.progress {
  color: royalblue;
  width: 300px;
  height: 20px;
  background: linear-gradient(currentColor, currentColor) 0 0 / attr(value %) 100% no-repeat #ccc;
  border-radius: 2px;
  position: relative;
}
.progress::after {
  content: attr(value);
  position: absolute;
  top: 50%;
  left: 100%;
  transform: translate(10px, -50%);
  font-size: 20px;
}

你也可以访问在线demo真实体验:codepen.io/xboxyan/pen…

四、原子化的未来?

回头再来看看这种写法,是不是非常类似现在流行的原子化CSS?

<div w="100" h="100"></div>
<div w="200" h="100"></div>
<div w="300" h="100"></div>

嗯...等到兼容性没有问题后,现在的原子化框架都得革新了 ,只需要极少部分原子CSS即可适配大量的样式,而不是这样生成大量用到的样式

image-20250516195921515

attr可能就两行,类似这样

[fs]{
  font-size: attr(fs type(<length>))
}
p{
  padding: attr(p type(*))
}

是不是可以节省大量CSS代码?

五、优势和局限

其实很多特性和CSS变量还是比较相似,不过相比而言还是有不少优势的

  1. 支持content内容生成
  2. html结构更直观,个人觉得CSS变量放在style上有些冗余
  3. 天然原子化,比现在框架生成要高效的多

然后有一个局限性,那就是不支持链接格式,比如

<div src="xxx.png"></div>

如果直接这样使用,是不会生效的

div{
  background: url(attr(src)); /*无效*/
}

只能用这种形式,其实和现在CSS变量差不多了

<div src="url(xxx.png)"></div>

官方说明是为了安全考虑,不能用于动态构造 URL

😭太可惜了,一直想用这个功能能实现自定义 img 标签,将图片转成背景图片,这样就能做更多事情了

<img src="xxx.png">
<style>
  img{
    background: url(attr(src));
  }
</style>

总之,这是一个未来非常有潜力的新特性,敬请期待吧。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发 ❤❤❤

❌
❌