最近,即将支有一则非常振奋人心的持嵌消息,CSS 即将原生支持嵌套 -- Agenda+ to publish FPWD of Nesting[1],预处已无用武表示 CSS 嵌套规范即将进入规范的理器 FWPD 阶段。 目前对应的即将支规范为 -- CSS Nesting Module[2]。 随着 CSS 自定义属性(CSS Variable)的持嵌大规模兼容,到如今 CSS 即将支持嵌套,预处已无用武一些预处理器的理器核心功能已经被 CSS 原生支持,这是即将支否表示 SASS/LESS 等预处理器已无用武之地?即将被淘汰了? 首先简单介绍一下,一个规范从提出到落地,持嵌会经历的预处已无用武一些阶段: 上文说的,即将进入 FPWD,理器只是即将支处于规范的第 2 个阶段 WD 阶段,FPWD 表示第一次公开工作草案( First Public Working Draft (FPWD))。持嵌FPWD 后面还会有数个工作草案,预处已无用武会处理来自 CSSWG 内部和小组外部更广泛社会的反馈。完善规范的设计。 也就是说,目前来看,即便后面的服务器托管流程顺利,要等到浏览器大范围实现该规范到能落地的那天还有非常长一段时间。 除此之外,我觉得 SASS\LESS 等预处理器还有一些比较有意思的功能(函数),是即便原生 CSS 支持了自定义属性和嵌套之后依旧欠缺的,我简单罗列罗列我的看法。 目前,原生 CSS 依旧不支持循环函数。 但是其实在预处理器中,循环还算是比较常用的一个功能。考虑下面这种布局: ul 下面有多个 li,每个 li 的高度递增 20px,一个一个写当然也可以,但是有了循环其实能极大减少工作量: 如果没有预处理器,我们的 CSS 可能是这样的: 如果利用 SASS 预处理器,可以简化成: 当然,除此之外,在非常多的复杂 CSS 动画效果中,循环是源码下载非常非常常用的功能。 譬如一些粒子动画,我们通常可能需要去操纵 50~100 个粒子,也就是 50~100 个 div 的样式,甚至更多,如果没有循环,一个一个去写效率会大打折扣。 下面我简单罗列一些我实现过的,运用到了 CSS 预处理器循环功能的动画效果。 像上面这个使用纯 CSS 实现的火焰效果,其中的火焰的动态燃烧效果。其实是通过大量的细微粒子的运动,配合滤镜实现。 其中使用到了 SASS 的循环函数的片段: 嗯哼,上面的循环是循环了 200 次之多,如果真要一个一个写,工作量还是源码库非常巨大的。上述效果的完整代码,你可以戳这里: CodePen Demo -- CSS Candles[3] 接下来一个就是 if() 条件语句。 其实,CSS 中有一类非常类似条件语句的写法,也就是媒体查询 @media 以及 特性检测 @supports 语句,目前 CSS 中支持的类似条件选择的一些写法如下: CSS @supports 通过 CSS 语法来实现特性检测,并在内部 CSS 区块中写入如果特性检测通过希望实现的 CSS 语句。 上述 CSS 语句的意思是如果客户端支持 position:sticky,则采用 position:sticky,否则,就是 position:fixed。 关于 CSS 特性检测的深入讲解,你可以看看我的这篇文章:深入探讨 CSS 特性检测 @supports 与 Modernizr[4] 另外一种常见的条件语句就是媒体查询,这个大家还是比较熟悉的。 如果当前设备满足一种什么条件,则怎么样怎么样。 嗯,并且,上述的两种条件语句可以互相嵌套使用: 不过,上述两种毕竟不是严格意义上的我们期待的 if() 语句。 很久之前,社区就有声音(css-values - if() function[5]),提议 CSS 规范中实现 if() 条件语句,类似于这样: 可以看到这一语句 if(var(--calc) < 12px, 12px, var(--calc)) 类似于一个三元语句,还是比较好理解的。 然而,上述的条件语句一直没得到支持的原因,在 scss-values - if() function[6] 可以略窥一二。 原因是 CSS 一直在尽量避免在属性当中产生任意依赖。在 CSS 中,属性之间本身存在一些隐式依赖,譬如 em 单位长度受到父元素的 font-size 的影响,如果作者能够添加任意依赖关系(通过 if() 条件语句),那么将会导致一些问题。 所以,CSS 中的直接 if() 语句一直没有得到实现。 最后,我们来看看预处理器中对 if() 的运用,由于 SASS 等预处理器最终还是要编译成 CSS 文件,所以 if() 其实并不太常用。因为 SASS 中的 if() 也无法实现类似上述说的 font-size: if(var(--calc) < 12px, 12px, var(--calc)) 这种功能。 在 SASS 中,我认为最常用的 if() 可能也就是这种场景: 上述代码是对 CSS 实现三角形的一个封装,通过传入的参数,实现不同方向、颜色、大小的三角形。也就是预处理器中 if() ,更多的完成一些函数功能的封装,方便复用。 实际上述的代码会被编译成: OK,接下来这个是随机函数,是我个人在 SASS 等预处理器中最常用的一个函数。目前原生 CSS 不支持任意形式的随机。 在 CSS 动画效果中,非常多的因素我们不希望是一成不变的,我们希望的是,一些属性的值的产生由我们设定一个基础规则,一个范围中得到,这样每次刷新都能产生不同的效果。 最常见的莫过于不同的颜色、不同的长度、不同的数量等等等等。 譬如下面这个使用 CSS 实现的效果:夏日夕阳图[7]。 我们通过随机,每次刷新都可以得到高度/宽度不一样,位置不一样的 div 块,利用随机的特性,绘制一幅幅不一样的效果图: DEMO -- 夏日夕阳图[8] 目前原生 CSS 不支持任意形式的随机。使用预处理器,也只能是在编译前编写随机函数,SASS 中比较常用的随机函数的一些写法: random() 是 SASS 支持的一种函数,上述 $r 就能得到一个 0 ~ 100 的随机整数。 利用 random(),就能封装出各种随机函数,譬如随机颜色: 下面这个是社区对原生 CSS 实现 random() 函数的一些思考,感兴趣的可以猛击: [css-values] random() function[9] 简单搬运其中一些比较有意思的观点。 假设 CSS 原生实现了 random() 函数,譬如下述这个写法: 假设其中 ramdom() 是原生 CSS 实现的随机函数,有一些事情是需要被解决或者得到大家的认可的: 上述的问题可以归结于如果 CSS 原生支持随机,随机值的持久化和更新是必须要解决的问题。总之,目前看来,未来 CSS 原生支持随机的可能性还是很大的。 工具函数:颜色函数、数学函数 最后,我们再来看看一些有意思的工具函数。目前原生 CSS 暂时不支持一些比较复杂的颜色函数和数学函数。但是预处理器都带有这些函数。 在我之前的一篇关于阴影的文章中 -- 你所不知道的 CSS 阴影技巧与细节[10],介绍过一种利用多重阴影实现立体阴影的效果,譬如我们要实现下面这个效果: 其中的阴影的颜色变化就借助了 SASS 的颜色函数: 当然,除了上述的两个颜色函数,SASS 还提供了非常多类似的颜色相关的函数,可以看看这里:Sass基础—颜色函数[11]。 除了颜色,数学函数也是经常在 CSS 效果中会需要用到的。 我在这篇文章中 -- 在 CSS 中使用三角函数绘制曲线图形及展示动画[12],专门讲了如何利用 SASS 等预处理器实现三角函数,以实现曲线线条,实现一些有意思的效果,像是这样: 当然,目前 SASS 也不支持三角函数,但是我们可以利用 SASS function,实现一套三角函数代码: 就目前原生 CSS 而言,在数学函数等方面其实已经做出了非常多的努力,譬如: 等兼容性已经逐渐铺开,可以开始大规模使用,而类似于 也在规范 CSS Values and Units Module Level 4[13] 中被提及定义,相信不久的将来也会逐渐落地。 关于社区对数学函数的一些讨论,感兴趣的也可以看看这里:Mathematical Expressions[14] 好了,综上总结一下,就目前而言,我觉得 SASS/LESS 等预处理器在很多方面还是有有用武之地的,在上述的一些功能原生 CSS 没有完全落地之前,预处理器能一定程度上弥补 CSS 的不足。 并且,除去上述说的一些我个人认为比较重要有意思的功能、函数之外,预处理器其它一些核心功能,譬如 extend、mixins 等也能有效的提升开发时的效率。 所以,在未来的一段时间内,我认为预处理器还是能和 CSS 友好共存~ 好了,本文到此结束,希望对你有帮助 :) [1]Agenda+ to publish FPWD of Nesting: https://lists.w3.org/Archives/Public/www-style/2021Mar/0019.html [2]CSS Nesting Module: https://drafts.csswg.org/css-nesting/ [3]CodePen Demo -- CSS Candles: https://codepen.io/Chokcoco/pen/jJJbmz [4]深入探讨 CSS 特性检测 @supports 与 Modernizr: https://www.cnblogs.com/coco1s/p/6478389.html [5]css-values - if() function: https://github.com/w3c/csswg-drafts/issues/3455 [6]scss-values - if() function: https://github.com/w3c/csswg-drafts/issues/3455 [7]夏日夕阳图: https://csscoco.com/inspiration/#/./cssdoodle/sunset [8]DEMO -- 夏日夕阳图: https://csscoco.com/inspiration/#/./cssdoodle/sunset [9][css-values] random() function: https://github.com/w3c/csswg-drafts/issues/2826 [10]你所不知道的 CSS 阴影技巧与细节: https://github.com/chokcoco/iCSS/issues/39 [11]Sass基础—颜色函数: https://www.sass.hk/skill/sass25.html [12]在 CSS 中使用三角函数绘制曲线图形及展示动画: https://github.com/chokcoco/iCSS/issues/72 [13]CSS Values and Units Module Level 4: https://drafts.csswg.org/css-values-4/#exponent-funcs [14]Mathematical Expressions: https://drafts.csswg.org/css-values/#math规范的几个阶段
for() 循环函数
利用预处理器循环功能实现的一些效果展示
if() 条件语句
@support 条件语句
@media 条件语句
SASS 等预处理器中的 if() 语句
Random() 随机函数
关于原生 CSS 实现 random() 的一些思考
总结一下
最后
参考资料