使用CSS变量,让你的CSS更精彩
时间:2023-03-21 01:26:47
科技观察
前言“CSS变量”也叫“CSS自定义属性”。怎么突然提这个很少人用的东西?因为最近重构了自己的官网,不知道为什么突然喜欢用“CSS变量”。或许它隐藏的魅力让笔者为之倾倒吧。说到CSS为什么要用变量,我们举个栗子,估计大家一看就明白了。/*不使用CSS变量*/.title{background-color:red;}.desc{background-color:red;}/*使用CSS变量*/:root{--bg-color:red;}.title{background-color:var(--bg-color);}.desc{background-color:var(--bg-color);}看完之后,你可能会觉得使用“CSS变量”的代码量是有点多,不过有想不到有一天,邪恶的策划师兄和设计小姐姐说要做一个换皮功能。按照通常的思路,估计有的同学会根据默认的颜色主题添加一个新的颜色主题CSS文件进行对比。每次有新的需求要同时维护好几套主题色是多么的麻烦啊。这时候,“CSS变量”就派上用场了。可以事先和设计小姐姐指定需要更改的颜色,通过“CSS变量”定义,通过JS批量操作这些定义好的“CSS变量”。这也是“换主题色”的解决方案之一。好处是只需要写一套CSS代码。["red","blue","green"].forEach(v=>{constbtn=document.getElementById(`${v}-theme-btn`);btn.addEventListener("click",()=>document.body.style.setProperty("--bg-color",v));});这里总结一下在CSS中使用变量的好处:减少样式代码的重复增加样式代码的可扩展性提高样式代码的灵活性增加一种CSS和JS之间的通信方式,无需深入遍历DOM来改变某个style可能有同学会问,Sass和Less都已经实现了变量的特性,何必呢。但是仔细想想,“CSS变量”相对于Sass和Less的变量还是有它的优势的。浏览器的原生特性可以直接运行DOM对象的一个??成员,不需要任何的翻译,极大的方便了CSS和JS的衔接如果有很多,感觉没必要。贴上阮一峰老师写的教程《CSS变量教程》。同时笔者也对“CSS变量”的细节进行了整理,方便大家记忆。声明:--变量名读作:var(--变量名,默认值)typenormal:只能作为属性值,不能作为属性名字符:与字符串“Hello,”连接var(--name)value:使用带有数值单位的calc(),使用var(--width)*10px作用域:在当前元素块作用域及其子元素块作用域范围内有效优先级:内联样式>ID选择器>类选择器=属性选择器=伪类选择器>标签选择器=伪元素选择器下面通过几个特殊场景来展示“CSS变量”的魅力。还是那句话,“有使用场景的东西,自然就有它的价值”,用的人会越来越多。使用场景事实上,“CSSVariables”有一个特别有用的场景,那就是可以和List元素的集合结合使用。如果您不明白这是什么,请继续阅读。下面所有的demo代码都是基于vue文件,但是html、css、js是分开写的。为了简化CSS编写,使用Sass进行预处理,方便代码演示。一个barloadingbar通常由几行组成,每行对应同一个动画不同的延时,通过时间差运行同一个动画产生loading效果。估计大部分同学可能会把CSS代码写成下面这样。.loading{width:200px;height:200px;li{border-radius:3px;width:6px;height:30px;background-color:#f66;animation:beat1sease-in-outinfinite;&+li{margin-left:5px;}&:nth-child(2){animation-延迟:200ms;}&:nth-child(3){animation-delay:400ms;}&:nth-child(4){animation-delay:600ms;}&:nth-child(5){animation-delay:800ms;}&:nth-child(6){animation-delay:1s;}}}分析代码发现每个只是animation-delay不同,其余代码完全一样,换成其他类似的List如果有10个,写10:nth-child。显然,这种方式不够灵活,也不容易封装成组件。如果能像JS一样封装成一个函数,根据参数输出不同的样式效果就更好了。说了这么多,显然是为了铺垫“CSS变量”的开发技巧。对于HTML部分的修改,让每个在自己的作用域下都有一个“CSS变量”。对于CSS部分的修改,需要分析哪些属性随着索引的增加有规律的变化,将规律变化的部分替换为“CSS变量”表达式。/ul>.strip-loading{width:200px;height:200px;li{--time:calc((var(--line-index)-1)*200ms);border-radius:3px;width:6px;height:30px;background-color:#f66;animation:beat1.5sease-in-outvar(--time)infinite;&+li{margin-left:5px;}}}代码中可以获取源码链接文章末尾的变量--line-index和--time使每个都有自己的作用域。比如第二个中,--line-index的值为2,--time的计算值为200ms。换成第三个后,这两个值又会不一样了。这是由于“CSS变量”的作用域(在当前元素及其子元素的块作用域下有效),所以在.strip-loading的块作用域下调用--line-index是无效的。/*flex属性无效*/.loading{display:flex;align-items:center;flex:var(--line-index);}通过使用“CSS变量”,CSS代码也从29行减少到15行,对于那些包含多组List元素的场景,效果更明显。而且这种写法更美观,也更容易维护。有一天,据说加载效果的时间差不明显。只需将calc((var(--line-index)-1)*200ms)中的200ms调整为400ms。无需修改每个:nth-child(n)。心形加载条前段时间在用掘金的时候看到陈大鱼头哥的心形加载条,觉得很漂亮,也很有意思。通过动画分析,发现每行的背景色与动画延迟不一致,动画的高度也不一致。细心的话,你可能还会发现第1条和第9条的高度相同,第2条和第8条的高度相同,以此类推,得到同类型高度变换的公式:对称指数=总数+1-指数。背景色使用滤镜的hue-rotate功能,使颜色过渡更自然;动画延迟设置和上面barloadingbar的设置一致。让我们根据您看到的动画使用“CSS变量”来实现它。
.heart-loading{width:200px;height:200px;ul{display:flex;justify-content:space-between;width:150px;height:10px;}li{--Θ:calc(var(--line-index)/var(--line-count)*.5turn);--time:calc((var(--line-index)-1)*40ms);border-radius:5px;width:10px;height:10px;background-color:#3c9;filter:hue-rotate(var(--Θ));animation-duration:1s;animation-delay:var(--time);animation-iteration-count:infinite;}.line-1,.line-9{animation-name:line-move-1;}.line-2,.line-8{动画名称:line-move-2;}.line-3,.line-7{动画名称:line-move-3;}.line-4,.line-6{animation-name:line-move-4;}.line-5{animation-name:line-move-5;}}源码链接可在文末一波后获取的操作,会有如下效果。与陈大鱼头的心形加载条相比,颜色、波动曲线和跳动频率都有些不同。随着暖色的蔓延和肾上腺素的激增,这是一种心跳加速的感觉。想起自己曾经写过的一首诗:见之怜惜,放不下。标签导航栏上的两个加载栏演示了CSS中“CSS变量”的使用和一些神奇的技巧。现在,通过标签导航栏来演示“CSS变量”在JS中的使用。JS中操作“CSS变量”的API主要有3个,看起来简单易记,分别是:读取变量:elem.style.getPropertyValue()设置变量:elem.style.setProperty()删除变量:elem.style.removeProperty()先上传效果图。该效果主要使用“CSS变量”来标记各个Tab的背景色,切换Tab的显示状态。
.tab-navbar{display:flex;overflow:hidden;flex-direction:column-reverse;border-radius:10px;width:300px;height:400px;nav{display:flex;height:40px;background-color:#f0f0f0;line-height:40px;text-align:center;a{flex:1;cursor:pointer;transition:all300ms;&.active{background-color:#66f;字体粗细:粗体;颜色:#fff;}}}div{flex:1;ul{--tab-index:0;--tab-width:calc(var(--tab-count)*100%);--tab-move:calc(var(--tab-index)/var(--tab-count)*-100%);display:flex;flex-wrap:nowrap;width:var(--tab-宽度);高度:100%;转换:翻译e3d(var(--tab-move),0,0);transition:all300ms;}li{display:flex;justify-content:center;align-items:center;flex:1;background-color:var(--bg-color);font-weight:bold;font-size:20px;color:#fff;}}}exportdefault{data(){return{index:0,list:["#f66","#09f","#3c9"]};},方法:{select(i){this.index=i;this.$refs.tabs.style.setProperty("--tab-index",i);}}};源码链接可在文末获取。在
上定义--tab-index以指示选项卡的当前索引。单击按钮时,重置--tab-index的值以在不操作DOM的情况下移动。position显示指定的Tab不操作DOM但是可以移动,因为定义了--tab-move,--tab-index和--tab-move的关系是通过calc()计算出来操作的transform:translate3d()移动。另外,在- 上定义--bg-color代表Tab的背景色也是一种比较简单的模板赋值方式,比写要好。如果多个CSS属性依赖于一个变量赋值,使用“CSS变量”给样式赋值会更方便。那些CSS属性可以在CSS文件中计算赋值,可以帮助JS分担一些属性计算工作。当然,这个分页式导航栏也可以通过纯CSS来实现。有兴趣的同学可以看看笔者上一篇文章中的纯CSS分页式导航栏。浮动追踪按钮通过几个栗子实践了CSS和JS中“CSS变量”的使用。相信大家都已经掌握了它的用法和技巧。之前在某网站看到一个很酷的鼠标悬停效果,好像是用“CSS变量”实现的。作者也是用“CSS变量”凭记忆实现的。其实思路比较简单,先对按钮进行布局和着色,然后用伪元素标记鼠标的位置,定义--x和--y表示伪元素在按钮中的坐标,并通过JS获取鼠标在按钮上的offsetLeft和offsetLeft,将offsetLeft分别赋值给--x和--y,然后给伪元素加上径向渐变背景色,就大功告成了,酷酷的鼠标悬停跟踪效果诞生了。使用CSS变量让你的CSS更精彩.track-btn{display:block;overflow:hidden;border-半径:100px;宽度:400px;高度:50px;背景颜色:#66f;行高:50px;光标:指针;字体粗细:粗体;字体大小:18px;颜色:#fff;跨度{位置:相对;}&::before{--size:0;position:absolute;left:var(--x);top:var(--y);width:var(--size);height:var(--大小);背景图像:径向渐变(circleclosest-side,#09f,transparent);内容:"";转换:translate3d(-50%,-50%,0);transition:all200msease;}&:hover::before{--size:400px;}}exportdefault{name:"track-btn",methods:{move(e){constx=e.pageX-e.target.offsetLeft;consty=e.pageY-e.target.offsetTop;e.target.style.setProperty("--x",`${x}px`);e.target.style.setProperty("--y",`${y}px`);}}};源码链接可在文末获取。其实可以结合鼠标事件实现更炫酷的效果,比如动画关联,事件响应等操作。没有不可能,只有想不到,发挥你的想象力。之前在CodePen上看到一个很好的栗子,一个悬浮的视差按钮,具体代码涉及到3D变换的一些知识。看完源码,按照它的思路自己实现。顺便把代码稍微改进一下,封装成一个Vue组件,存放在本课件的示例代码中。感觉录制的GIF有点别扭,显示效果不是很好。有兴趣的同学可以下载本课件的示例代码,运行看看效果。兼容性对于现代浏览器来说,“CSS变量”的兼容性其实还是相当不错的,大家可以放心使用。毕竟现在是各大浏览器厂商快速迭代的时候了。产品在用户体验中占很大比重。所以,如果条件允许,还是大胆尝试新事物为好,不要拘泥于过去的一些所谓的规范。还有多少人愿意维护IE6~IE9的兼容性?如果一款产品的用户体验受限于古浏览器的打压(可能不包括政务类Web应用和金融类Web应用),我相信这款产品不会消失。非常远。在完成一个产品的过程中,我们不仅仅是为了完成工作任务。如果能在保证进度的情况下花一点时间美化一下,说不定会有意想不到的收获。“用心写每一段代码,才是享受写代码的真谛。”小结本文循序渐进地探讨“CSS变量”的使用和技巧。这么好用的功能当然不能放过。其实多想想,很多场景下都可以使用“CSS变量”。作者将本文提到的例子统一成一个Demo,也方便有兴趣的同学通过课件的示例代码进行学习,思考一些阅读本文时可能没有注意到的细节。演示示例:条形加载条、心形加载条、标签导航栏、悬浮追踪按钮、悬浮视差按钮演示地址:关注智商前端,扫描文章底部二维码,回复后台变量获取《整套课件示例代码》演示操作:里面的readme.html有详细说明,记得看完,送你一个大大的彩蛋,暖心的彩虹语气🌈匹配的爱按钮。如果觉得这篇文章写得不错,请给作者点个赞,如下图。当然彩蛋源码也在课件示例代码中。想了解更多CSS开发技巧,可以移步作者2019年写的一篇92000阅读量的热门文章《灵活运用CSS开发技巧(66个骚操作案例)》,保证满足你的关注。