CSS 魔法!如何将任意 CSS 类型转换为数值?
在 CSS 中有各式各样的类型值,例如 1rem、10vw、100cqw 等等,这些相对值给与了 CSS 强大的适应能力。但有时候,我们还需要知道这些相对值所对应的真实值,也就是 px 值,比如在移动端,我们经常会设置这样的根字号:
那么,p 此时的真实 px 值应该是多少呢?
在以往,我们只能通过 JS 去获取,但是现在,仅仅凭 CSS 也能做到,一起了解一下吧!
一、CSS 三角函数
从理论上来讲,将一个长度除以 1px 就应该得到具体的数值,相当于将这个长度以 1px 被分成了多少份。
但是,大家可能都知道,calc 在进行除法运算时,除数是不能带单位的。
不排除浏览器以后会支持。
不过现在终于迎来了转机,在 Chrome 111 中,CSS 新增了一系列三角函数。
sin()[1]:正弦
cos()[2]:余弦
tan()[3]:正切
asin()[4]:反正弦
acos()[5]:反余弦
atan()[6]:反正切
atan2()[7]:反正切
这里我们不聊三角函数的作用,只是作为一个桥梁中转一下。
关于「正切函数」,这里简单回顾一下高中数学
在「直角三角形」中,其中一个锐角的「对边」和「临边」的比值就是这个角的「正切值」,「反正切」就是通过两条直角边反向去求出该角的「弧度值」,示意如下:
这些函数本身没什么特别的,业界通用,但有一个非常例外,那就是 atan2,它和 atan 作用是一样的,都是反正切函数。唯一的区别是,atan2 支持两个值
前端中的 atan 就是数学中的 arctan。
例如:
看似好像没啥意义,直接用 tan 不就好了?
和 JS 不同的是,CSS 中还能「支持单位」,如下:
这就不得了了,如果此时的 1rem 是 16px,那么浏览器会根据 1rem 的真实长度和 20px 做对比,相当于让两个带单位的长度做除法运算。
也就是说,y/x 的值可以得到两个 CSS 长度之间的真实比值,而无需额外转换。
然后,通过正切函数 tan 将括号里面的值解析出来。
这一点其实在 JS 中也可以验证一下,只是 CSS 可以带单位的值。
如果将后面的值设置为 1px,就相当于把任意长度按照 1px 进行切分,也就得到了任意长度的 px 数值,如下:
有了这个不带单位的绝对值,我们就可以做很多事情了,下面举几个例子。
二、CSS 获取当前字号
回到文章开头的问题,如何通过 CSS 获取当前字号呢?
根据上一节的原理,只要通过 tan() 和 atan2()就可以将任意长度转换为数值了。
这样--px-font 就得到了真实的 px 数值。
然后,我们还可以借助 CSS 计数器,将这个数字渲染到页面。
结果...效果如下:
好像不太对?貌似是浏览器的 bug,这种情况下忽略了 tan(atan2(1rem, 1px))中的 1rem 单位。
要修复这个问题其实很容易,需要通过 @property 定义一个 CSS 变量,类型为长度,然后将需要计算的值赋给这个变量,如下:
这样就正常了,在改变屏幕尺寸时会自动渲染出当前字号。
你也可以访问在线链接
CSS font-size (juejin.cn)[8]
CSS font-size (codepen.io)[9]
三、实时显示容器尺寸
CSS 容器查询中出现了几个新的尺寸单位。这里只介绍下面两种。
关于容器查询,可以参考这篇文章:介绍 2022 最期待且已正式支持的 CSS container 容器查询 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com),本文并不涉及具体容器查询语句。
「cqw」 容器查询宽度(Container Query Width)占比。「1cqw 等于容器宽度的 1%」。假设容器宽度是 1000px,则此时 1cqw 对应的计算值就是 10px。
「cqh」 容器查询高度(Container Query Height)占比。「1cqh 等于容器高度的 1%」。
利用前面的技巧,可以将 cqw、cqh 这些单位转换为具体的 px 值。
假设有这样一个容器。
为了使容器尺寸生效,必须声明容器类型。
然后用同样的技巧,在伪元素中通过计数器将宽高渲染出来。
别忘了修复 bug。
效果如下,完全没有任何 JS。
你也可以访问在线链接
CSS resize (juejin.cn)[10]
CSS resize (codepen.io)[11]
四、自适应文本的头像
下面看一个自适应文本的头像,当文本较多时,会自动缩放,让文本可以完整展示,如下
原理其实是通过容器尺寸的映射关系来动态设置文本大小,关键实现如下:
但是,通过文字大小来缩放有一个限制,在 PC 上,一般会有最小字号限制(通常是 12 号),所以更好的方式应该是通过scale
来实现。
现在,我们可以通过上面的技巧,将容器尺寸转换成 scale 能够识别的数值,通过文本宽度和容器尺寸的比值来确实缩放比例,关键实现如下:
这样就得到了完全自适应尺寸的文本头像了。
完整代码可以访问在线链接
CSS auto text avator (juejin.cn)[12]
CSS avator auto scale (codepen.io)[13]
五、总结一下
以上就是本文的全部内容了,介绍了一个非常巧妙并且有用的 CSS 小技巧,下面总结一下
CSS 有很多类型的尺寸,这些尺寸给与了 CSS 强大的适应能力。
从理论上讲,将一个长度除以 1px 就可以得到具体的数值,但是 calc 不支持。
CSS 反正切函数 atan2(y,x) 支持两个参数,并且还支持带 CSS 单位。
通过 tan(atan2(y,x))可以得到 y/x 的比值,如果 x 是 1px,可以得到 y 的实际 px 值。
利用这个技巧,可以将任意类型值转换为数值。
纯数值可以在各个地方都可以使用了,比如 scale(var(--n)),如果需要 px,直接 calc(var(--n) * 1px )。
参考资料:
[1]sin(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/sin。
[2]cos(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/cos。
[3]tan(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/tan。
[4]asin(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/asin。
[5]acos(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/acos。
[6]atan(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/atan。
[7]atan2(): https://developer.mozilla.org/zh-CN/docs/Web/CSS/atan2。
[8]CSS font-size (juejin.cn): https://code.juejin.cn/pen/7289041195483791416。
[9]CSS font-size (codepen.io): https://codepen.io/xboxyan/pen/XWoObZX。
[10]CSS resize (juejin.cn): https://code.juejin.cn/pen/7289046442864279591。
[11]CSS resize (codepen.io): https://codepen.io/xboxyan/pen/MWZLYZz。
[12]CSS auto text avator (juejin.cn): https://code.juejin.cn/pen/7289095309752270906。
[13]CSS avator auto scale (codepen.io): https://codepen.io/xboxyan/pen/qBLLexW。
版权声明: 本文为 InfoQ 作者【高端章鱼哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/d8c6375bd435d44734b5bbc32】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论