时隔两年,Chrome也支持round等CSS数学函数了

这篇文章发布于 2024年09月26日,星期四,00:04,归类于 CSS相关。 阅读 2614 次, 今日 15 次 一条评论

 

封面占位图

一、CSS又更强了一点

好消息,时隔两年,原本仅Safari浏览器支持的mod()/rem()/round()现在Chrome浏览器也支持啦。

数学函数兼容性

mod()函数

CSS mod()函数返回第一个参数除以第二个参数的取模结果,类似于JavaScript余数运算符(%)。

使用示意:

/* 数值,无单位 */
line-height: mod(7, 2); /* 1 */
line-height: mod(14, 5); /* 4 */
line-height: mod(3.5, 2); /* 1.5 */

/* 百分比或者带单位的尺寸 */
margin: mod(15%, 2%); /* 1% */
margin: mod(18px, 4px); /* 2px */
margin: mod(19rem, 5rem); /* 4rem */
margin: mod(29vmin, 6vmin); /* 5vmin */
margin: mod(1000px, 29rem); /* 72px - 如果根字号是16px */

/* 正负值 */
rotate: mod(100deg, 30deg); /* 10deg */
rotate: mod(135deg, -90deg); /* -45deg */
rotate: mod(-70deg, 20deg); /* 10deg */
rotate: mod(-70deg, -15deg); /* -10deg */

/* 计算*/
scale: mod(10 * 2, 1.7); /* 1.3 */
rotate: mod(10turn, 18turn / 3); /* 4turn */
transition-duration: mod(20s / 2, 3000ms * 2); /* 4s */

这个CSS函数日常开发使用的机会并不大。

rem()函数

CSS rem()函数返回第一个参数除以第二个参数后的余数,类似于JavaScript余数运算符(%)。

使用示意:

/* U数值,无单位 */
line-height: rem(21, 2); /* 1 */
line-height: rem(14, 5); /* 4 */
line-height: rem(5.5, 2); /* 1.5 */

/* 百分比或者带单位的尺寸 */
margin: rem(14%, 3%); /* 2% */
margin: rem(18px, 5px); /* 3px */
margin: rem(10rem, 6rem); /* 4rem */
margin: rem(26vmin, 7vmin); /* 5vmin */
margin: rem(1000px, 29rem); /* 72px - if root font-size is 16px */

/* 正负值 */
rotate: rem(200deg, 30deg); /* 20deg */
rotate: rem(140deg, -90deg); /* 50deg */
rotate: rem(-90deg, 20deg); /* -10deg */
rotate: rem(-55deg, -15deg); /* -10deg */

/* 计算*/
scale: rem(10 * 2, 1.7); /* 1.3 */
rotate: rem(10turn, 18turn / 3); /* 4turn */
transition-duration: rem(20s / 2, 3000ms * 2); /* 4s */

rem和mod的区别

mod 函数生成一个为零或与除数具有相同符号的结果。
rem 函数生成一个为零或与被除数具有相同符号的结果。

这两个数学函数日常开发鲜有机会出场。

但是有个数学函数是例外,那就是round()函数,这个函数的语法更加复杂,但同时也更加实用。

二、实用必学round()函数

很多人以为round()函数就是简单的四舍五入,其实这个函数设计得非常巧妙,通过不同的参数设置,可以实现多种取值方法,例如(以JS API示意):

  • Math.ceil()
  • Math.floor()
  • Math.round()
  • Math.trunc()

都怎么实现的呢?看案例。

模拟Math.ceil()取值

Math.ceil()是向上取整,使用CSS语法表示则是:

canvas {
  border: round(up, 1.01px, 1px) solid;
}

结果渲染的边框宽度则是2px,实时渲染效果如下所示:

其中,up表示向上取整,第三个参数表示最终计算值需要可以被此数值整除,例如round(up, 2.01px, 2px)的计算值就是4px

canvas {
  border: round(up, 2.01px, 2px) solid;
}

实时渲染效果如下所示:

模拟Math.floor()取值

Math.floor()是向下取整,因此,下面CSS代码的边框大小就是1px。

canvas {
  border: round(down, 1.99px, 1px) solid;
}

模拟Math.round()取值

语法:

round( nearest, <valueToRound> , <roundingInterval> )

或者直接:

round( <valueToRound> , <roundingInterval> )

就是我们常说的四舍五入。

模拟Math.trunc()取值

语法:

round( to-zero, <valueToRound> , <roundingInterval> )

表示将valueToRound舍入为roundingInterval接近/接近零的最接近整数倍。

例如:

canvas {
  border: round(to-zero, 5.5px, 2px) solid;
}

边框宽度是4px,因为5.5px往0走,最靠近2px倍数的值就是4px。

效果示意:

而round(to-zero, 5.5px, 3px)的计算值就是3px,比5.5px小的又是3px备注的最大值就是3px。

效果示意:

二、round()函数的实际应用

举两个实用案例吧。

1. 让响应式font-size永远是整数

移动端开发会使用rem单位和屏幕尺寸关联,例如:

html {
  font-size: clamp(16px, calc(100% + 4 * (100vw - 375px) / 105), 20px);
}

此时,1rem对应的尺寸就有可能是小数。

小数就会有什么问题,例如一些SVG图标尺寸使用rem表示,由于出现了小数,图标边缘就很可能出现缝隙。

又或者是圆角边缘,或者box-shadow边缘出现很微小的缝隙风。

此时,就可以使用round()函数让尺寸取整,以规避这些问题。

使用示意:

<ul>
  <li>HTML并不简单</li>
  <li>CSS新世界</li>
  <li>好书推荐</li>
</ul>
ul {
  font-size: round(1rem, 1px);
}

此时,<ul>列表的字号大小一定是整数。

如果没有round四舍五入,则字号大小则就可能是小数。

参见下图GIF动态示意(不应用round是小数18.2476px,应用round()函数则是整数18px):

字号round取整示意

2. 模拟animation的steps()步阶函数效果

round()函数的最后一个参数表示取舍的最小数值单元,试想下,如果是一个0-100的动画,如果我们设置取整的单元是20,那岂不是应用round()函数后,最终的计算值只可能是0、20、40、60、80和100,不就和CSS动画中的steps()步阶函数很像了么?

例如有个静态的loading图标:

<img src="loading.png" class="spin" />

实际渲染效果如下,是个静态的:

则下面这段CSS代码就可以让此图标loading旋转效果:

.spin {
  transform: rotate(round(calc(var(--seed) * 3.6deg), 45deg));
  animation: seed 1s linear infinite;    
}
@property --seed {
  syntax: "<integer>";
  inherits: false;
  initial-value: 0;
}
@keyframes seed {
  from { --seed: 0; }    
  to { --seed: 100; }    
}

眼见为实,您可以狠狠地点击这里:使用CSS round()函数模拟steps动画demo

效果截图如下所示:

demo动画loading效果截图

是不是实现得非常巧妙!

虽然steps()函数可以实现一样的效果,但是steps()的学习和理解成本要比round()函数高多了,唯一的优势就是兼容性了。

不过这个例子也可以看出round()函数的应用潜力。

四、结语巴拉巴拉

目前,规范里面提及的数学函数大部分都已经支持了吧。

首先第一批支持的是min()/max()/clamp()这些数学函数,详见“了解CSS min()/max()/clamp()数学函数”一文。

再然后就是,sin()/cos()这些函数支持,去年开始支持的,之前也介绍过,参见“CSS sin()/cos()等数学三角函数简介与应用”一文。

其他数学函数,如求平方根的sqrt()函数,幂指数的pow()函数,返回给定数字的幂的数学常数e的特殊指数函数exp(),返回数字对数的log()函数,则是去年底支持的,算是第3波吧。

sqrt函数兼容性

然后就是本文这几个数值取舍函数,属于第4批次。

最后一波应该就是绝对值abs()函数,正负零判断的sign()的函数。

总之很奇怪,不知道为何Chrome浏览器不一次性支持,而是分5波进行。

好吧,就说这么多吧。

感谢阅读,欢迎

凌玉灵

(本篇完)

分享到:


发表评论(目前一条评论)

  1. He110说道:

    感觉最适合使用的是兼容响应式计算中,由于小数运算导致宽 / 高溢出,更新父容器宽 / 高,再重复此过程,最后导致的宽度无限变长问题