这篇文章发布于 2020年10月10日,星期六,23:56,归类于 CSS相关, JS实例。 阅读 24001 次, 今日 8 次 8 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9535
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
一、CSS attr()指定值类型的新语法简介
传统的attr()
语法只能让HTML属性作为字符串使用,且只能使用在伪元素中,例如:
<span data-title="提示">按钮</span>
span:hover::after { content: attr(data-title); }
但是全新的attr()
语法那可就完全不得了了,可以让HTML属性值转换成任意的CSS数据类型。
例如如下所示的HTML和CSS语句:
<button bgcolor="skyblue" radius="4">按钮</button> <button bgcolor="#00000040" radius="1rem">按钮</button> <button bgcolor="red" radius="50%">按钮</button> <button bgcolor="orange" radius="100% / 50%" title="by zhangxinxu(.com)">按钮</button>
button { background-color: attr(bgcolor color); border-radius: attr(radius px, 4px); }
也就是几个按钮的样式使用了新的attr()
语法进行设置,平常的按钮颜色、圆角都是在CSS中设定好的,这个例子中则不一样,颜色和圆角全部都是外部的HTML属性控制的。
理论上,上面的代码会有如下图所示的效果。
可以看出,如果浏览器支持了attr()
函数的值类型新语法,那么我们日常的组件开发就会迎来巨大的颠覆,许多组件的接口可以直接交给CSS完成,以及我们的开发会更灵活,可以节省大量的CSS代码和书写CSS的时间,例如:
[ml] { margin-left: attr(ml px, 0); } [mt] { margin-top: attr(ml px, 0); } [mr] { margin-right: attr(mr px, 0); } [mb] { margin-bottom: attr(mb px, 0); } [pl] { padding-left: attr(pl px, 0); } [pt] { padding-top: attr(pt px, 0); } [pr] { padding-right: attr(pr px, 0); } [pb] { padding-bottom: attr(pb px, 0); }
那么元素的margin
和padding
设置就不需要专门写在CSS样式中,直接在HTML中设置即可,支持任意的margin
和padding
大小,例如:
<div mt="10">上间距10px</div>
喔噢,看上去很厉害哦,HTML和CSS会一下子变得非常灵活与高效。
只可惜,attr()
函数的新语法目前没有任何浏览器支持,而且在我看来很长一段时间浏览器都不会支持,安全、性能等方面的影响太深远了。
不死心的我就琢磨着有没有什么办法让浏览器可以支持CSS attr()
函数的这个新语法呢?
然后想到了可以借助CSS变量作为信使实现Polyfill实现。
二、Polyfill attr()新语法
CSS变量有一个特性,那就是CSS自定义属性值支持各种表达式和函数值,哪怕这个表达式是不知所云的东西。
例如随便自定义一个名叫keyword()
的函数,然后使用如下所示的CSS调用:
body { --keyword: keyword(red, 50%); /* 合法 */ color: var(--keyword); }
结果浏览器认为语法是合法的(比方说下图语句没有出现删除线,说明语句是合法的):
//zxx: 如果你看到这段文字,说明你现在访问是体验糟糕的垃圾盗版网站,你可以访问原文获得很好的体验:https://www.zhangxinxu.com/wordpress/?p=9535(作者张鑫旭)
于是我们就可以利用CSS变量的这个特性Polyfill attr()
函数,原理如下。
实现原理
- CSS自定义属性作为信使传递
attr()
函数,保证语法的合法性,例如:button { --attr-bg: attr(bgcolor color); background-color: var(--attr-bg); }
- 获取⻚⾯所有的包含
attr()
函数的⾃定义属性; - 遍历并观察所有DOM,如果设置了对应的⾃定义属性,将
attr()
语法转换成浏览器识别的常规自定义属性语法。
基于上述原理,我写了个JavaScript脚本,大家只需要在页面中引入下面这段HTML代码,就可以畅快自如地使用attr()
函数的新语法了。
如何使用
页面头部引入下面下面这个JS文件。
<script src="./css-attr.js"></script>
css-attr.js这个JS文件下载可以访问这里:css-attr.js
然后正常使用CSS变量来实现attr()
效果即可,例如——
Polyfill测试
假设已经引入了css-attr.js,然后页面中有如下所示的HTML和CSS代码:
<button bgcolor="skyblue" radius="4">按钮</button> <button bgcolor="#00000040" radius="1rem">按钮</button> <button bgcolor="red" radius="50%">按钮</button> <button bgcolor="orange" radius="100% / 50%">按钮</button>
button { border: 0; padding: .5em 1em; } button { --attr-bg: attr(bgcolor color); background-color: var(--attr-bg); --attr-radius: attr(radius px, 4px); border-radius: var(--attr-radius); }
结果就有如下图所示的效果,按钮表现出了符合预期的效果。
同时,如果我们手动修改按钮元素的bgcolor
或radius
属性值,按钮的样式也会同步变化,眼见为实,您可以狠狠地点击这里:attr() polyfill后的按钮demo
实际开发中,按钮元素往往需要一个默认的主样式,此时可以通过属性选择器进行区分,例如:
button { color: #fff; background-color: deepskyblue; } button[bgcolor] { --attr-bg: attr(bgcolor color); background-color: var(--attr-bg); } button[radius] { --attr-radius: attr(radius px, 4px); border-radius: var(--attr-radius); }
这样自定义的HTML属性无论设置还是不设置都不会影响按钮的正常显示了。
其他
然后这里还有个测试页面,风格粗犷的那种,您可以狠狠地点击这里:CSS attr() polyfill测试demo
点击按钮会修改HTML属性,大家可以看到样式同步变化了,如下图所示:
补充于2020-12-01
相关JavaScript代码已经在gitee上开源了,地址是:https://gitee.com/zhangxinxu/css-attr-polyfill
也欢迎大家关注我的gitee账号。
三、结束语
CSS var()
函数的这种任意表达式特性还适用于CSS自定义语法支持的实现上,关于这个,我会下一篇文章专门介绍,敬请期待。
以上就是自己研究出来的一点小东西,旨在抛砖引玉,欢迎交流!
另外,Polyfill实现的attr()语法比原生的语法要更强大,因此支持复合的HTML属性值,例如:
<div m="10px 20px 30px 40px">上间距10px</div>
[m] { --m: attr(m); margin: var(--m); }
可以同时指定多个分享的margin属性。
然后兼容性这块,凡是支持CSS变量的浏览器都支持这里的attr()
新语法。
好,就说这么多,
如果你觉得本文的内容还算有趣,欢迎分享。
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9535
(本篇完)
- 巧借CSS var变量实现任意的CSS自定义语法 (0.690)
- CSS变量对JS交互组件开发带来的提升与变革 (0.495)
- 介绍一种CSS变量未定义语法也OK的小妙招 (0.495)
- 纯CSS实现未读消息超过100自动显示为99+ (0.453)
- CSS值类型文档大全 (0.335)
- 我是如何通过CSS向JS传参的 (0.244)
- 研究了下Houdini中的CSS Layout API (0.143)
- 了解HTML/HTML5中的download属性 (0.112)
- JS字符串补全方法padStart()和padEnd()简介 (0.112)
- 原来浏览器原生支持JS Base64编码解码 (0.112)
- JS检测CSS属性浏览器是否支持的多种方法 (RANDOM - 0.100)
非常棒,不过有一个缺陷: 在vue/react这种动态渲染中,好像不生效。必须每次在ui发生变化后,重新执行css-attr这个js才行。
应该不至于啊,我抽时间看看
这个特性可以干掉tailwind之类的原子库吗?
技术理论上完全可以~
挺好的,就是自定义属性不能同名。
[mt] { margin-top: attr(ml px, 0); }
大神,ml px字母错了
单感觉这样的话dom上面定义的属性值太多了,还要记住自己定义的属性值名称
确实不错, 不知道老师有没有试过能否支持背景图片路径的url函数呢?