一、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):
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
效果截图如下所示:
是不是实现得非常巧妙!
虽然steps()
函数可以实现一样的效果,但是steps()
的学习和理解成本要比round()
函数高多了,唯一的优势就是兼容性了。
不过这个例子也可以看出round()
函数的应用潜力。
四、结语巴拉巴拉
目前,规范里面提及的数学函数大部分都已经支持了吧。
首先第一批支持的是min()/max()/clamp()这些数学函数,详见"了解CSS min()/max()/clamp()数学函数"一文。
再然后就是,sin()
/cos()
这些函数支持,去年开始支持的,之前也介绍过,参见"CSS sin()/cos()等数学三角函数简介与应用"一文。
其他数学函数,如求平方根的sqrt()函数,幂指数的pow()函数,返回给定数字的幂的数学常数e的特殊指数函数exp(),返回数字对数的log()函数,则是去年底支持的,算是第3波吧。
然后就是本文这几个数值取舍函数,属于第4批次。
最后一波应该就是绝对值abs()函数,正负零判断的sign()的函数。
总之很奇怪,不知道为何Chrome浏览器不一次性支持,而是分5波进行。
好吧,就说这么多吧。
感谢阅读,欢迎分享!
(本篇完)