原子化的未來(lái)?了解一下全面進(jìn)化的CSS attr函數(shù)
CSS attr函數(shù)相信大家都用過(guò)了吧,通常會(huì)配合偽元素content動(dòng)態(tài)生成內(nèi)容,比如一個(gè)簡(jiǎn)易的tooltip。
<span class="css-tips" data-title="我是tooltip" >提示上</span>
通過(guò)attr動(dòng)態(tài)生成
.css-tips[data-title]:after {
content: attr(data-title);
/*...*/
}
效果如下:
image-20250516200454818
你可以訪問(wèn)這個(gè)鏈接查看完整demo: https://codepen.io/xboxyan/pen/MLJjWQ
不過(guò),之前僅僅支持字符串形式,對(duì)于數(shù)字、顏色等都無(wú)法識(shí)別,例如
<div w="10"></div>
<style>
div{
width: attr(w) /**不生效/
}
</style>
現(xiàn)在,CSS attr迎來(lái)了全面進(jìn)化(chrome 133+),很多問(wèn)題都得到了很好的解決,一起看看吧~
一、快速上手
比如這樣一個(gè)結(jié)構(gòu),是不是看著有些眼熟?
<div w="100" h="100"></div>
<style>
div{
background: royalblue;
}
</style>
那么,如何讓屬性上的尺寸傳遞應(yīng)用到實(shí)際的寬高上呢?你可以這樣
[w]{
width: attr(w px)
}
[h]{
height: attr(h px)
}
來(lái)看看效果:
image-20250516170508419
我們可以用之前的規(guī)則,將尺寸通過(guò)content顯示出來(lái)
div:before{
content: attr(w) '*' attr(h);
color: white;
font-size: 14px;
}
效果如下:
image-20250516170636866
更為關(guān)鍵的是,這些完全是自動(dòng)獲取的,你可以設(shè)置多個(gè)任意尺寸
<div w="100" h="100"></div>
<div w="200" h="100"></div>
<div w="300" h="100"></div>
效果如下:
image-20250516170814615
是不是非常靈活?
二、語(yǔ)法詳解
現(xiàn)在來(lái)看看語(yǔ)法規(guī)則
attr(<attr-name> <attr-type>? , <fallback-value>?)
其實(shí)相比之前的規(guī)則,多了兩個(gè)可選參數(shù),一個(gè)是attr-type,表示屬性類型,完整類型可以參考
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Values_and_Units/CSS_data_types
還有一個(gè)是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")
前面的例子其實(shí)帶類型的值,除了使用px,還可以使用任何已有的CSS單位,比如
<div w="100" h="100" rotate="45"></div>
這里定義了一個(gè)旋轉(zhuǎn)角度,可以直接加上角度單位deg
[rotate]{
rotate: attr(rotate deg)
}
效果如下:
image-20250516172610893
但是,有些值其實(shí)是不帶單位的,比如顏色,并沒有什么后綴單位,比如
<div w="100" h="100" rotate="45" bg="red"></div>
這時(shí),可以采用type來(lái)手動(dòng)指定
[bg]{
background: attr(bg type(<color>));
}
效果如下:
image-20250516181308281
有些屬性可能不止一種類型,比如background,支持顏色,也支持漸變,還支持圖像,這里其實(shí)也能定義多種類型
[bg]{
background: attr(bg type(<color>|<image>));
}
我們換成漸變?cè)囋嚕?/p>
<div w="100" h="100" rotate="45" bg="linear-gradient(orange,red)"></div>
也能完美適配
image-20250516182249509
多個(gè)值寫起來(lái)可能比較麻煩,可以用「通配符」來(lái)代替,相當(dāng)于傳入什么,讀取的就是什么
[bg]{
background: attr(bg type(*));
}
最后就是回退值,非常類CSS變量,當(dāng)屬性不存在時(shí)(注意不能是空),采用回退值,比如
div{
background: attr(bg type(*), royalblue);
}
現(xiàn)在去除bg屬性
<div w="100" h="100" rotate="45"></div>
就回到了默認(rèn)的寶藍(lán)色
image-20250516183003948
你也可以訪問(wèn)在線demo真實(shí)體驗(yàn): https://codepen.io/xboxyan/pen/dPPremp
三、帶數(shù)字顯示的進(jìn)度條
下面來(lái)看一個(gè)案例:
image-20250516185648485
在過(guò)去,如果想用單個(gè)標(biāo)簽、單一變量來(lái)實(shí)現(xiàn),通常會(huì)用到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>
進(jìn)度很好辦,直接用這個(gè)變量計(jì)算就好了,那后面的數(shù)字怎么辦呢?直接使用變量是不行的
::before{
content: var(--value) /*不生效*/
}
其實(shí)可以用計(jì)數(shù)器來(lái)實(shí)現(xiàn),類似于這樣
.progress::before {
--value: 50;
counter-reset: progress var(--value);
content: counter(value);
}
有興趣可以查看張老師的這篇文章: 小tips: 如何借助content屬性顯示CSS var變量值[1]
不過(guò)計(jì)數(shù)器在正常場(chǎng)景下不支持小數(shù),導(dǎo)致有些場(chǎng)景受限
如果需要展示小數(shù)可以參考這篇文章: 如何讓CSS計(jì)數(shù)器支持小數(shù)的動(dòng)態(tài)變化?[2]
現(xiàn)在有了attr,可以直接用屬性來(lái)實(shí)現(xiàn),實(shí)現(xiàn)更方便
<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>
直接通過(guò)漸變繪制進(jìn)度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;
}
你也可以訪問(wèn)在線demo真實(shí)體驗(yàn):https://codepen.io/xboxyan/pen/JoozZry
四、原子化的未來(lái)?
回頭再來(lái)看看這種寫法,是不是非常類似現(xiàn)在流行的原子化CSS?
<div w="100" h="100"></div>
<div w="200" h="100"></div>
<div w="300" h="100"></div>
嗯...等到兼容性沒有問(wèn)題后,現(xiàn)在的原子化框架都得革新了 ,只需要極少部分原子CSS即可適配大量的樣式,而不是這樣生成大量用到的樣式
image-20250516195921515
用attr可能就兩行,類似這樣
[fs]{
font-size: attr(fs type(<length>))
}
p{
padding: attr(p type(*))
}
是不是可以節(jié)省大量CSS代碼?
五、優(yōu)勢(shì)和局限
其實(shí)很多特性和CSS變量還是比較相似,不過(guò)相比而言還是有不少優(yōu)勢(shì)的
- 支持content內(nèi)容生成
- html結(jié)構(gòu)更直觀,個(gè)人覺得CSS變量放在style上有些冗余
- 天然原子化,比現(xiàn)在框架生成要高效的多
然后有一個(gè)局限性,那就是不支持鏈接格式,比如
<div src="xxx.png"></div>
如果直接這樣使用,是不會(huì)生效的
div{
background: url(attr(src)); /*無(wú)效*/
}
只能用這種形式,其實(shí)和現(xiàn)在CSS變量差不多了
<div src="url(xxx.png)"></div>
官方說(shuō)明是為了安全考慮,不能用于動(dòng)態(tài)構(gòu)造 URL
??太可惜了,一直想用這個(gè)功能能實(shí)現(xiàn)自定義 img 標(biāo)簽,將圖片轉(zhuǎn)成背景圖片,這樣就能做更多事情了
<img src="xxx.png">
<style>
img{
background: url(attr(src));
}
</style>