现代 CSS 解决方案:CSS 数学函数 (下)

简介: 现代 CSS 解决方案:CSS 数学函数 (下)

calc 搭配自定义变量时候的默认值


还是上述的 Loading 动画效果,如果我的 HTML 标签中,有一个标签忘记填充 --delay 的值了,那会发生什么?


像是这样:


<div class="g-container">
    <div class="g-item" style="--delay: 0"></div>
    <div class="g-item" style="--delay: 0.6"></div>
    <div class="g-item"></div>
    <div class="g-item" style="--delay: 1.8"></div>
    <div class="g-item" style="--delay: 2.4"></div>
</div>
{
    animation-delay: calc(var(--delay) * -1s);
}


由于 HTML 标签没有传入 --delay 的值,并且在 CSS 中向上查找也没找到对应的值,此时,animation-delay: calc(var(--delay) * -1s) 这一句其实是无效的,相当于 animation-delay: 0,效果也就是少了个球的效果:


1fb7592579b7488d8ccd42dcbed5c070_tplv-k3u1fbpfcp-zoom-1.png


所以,基于这种情况,可以利用 CSS 自定义变量 var() 的 fallback 机制:


{
    // (--delay, 1) 中的 1 是个容错机制
    animation-delay: calc(var(--delay, 1) * -1s);
}

此时,如果没有读取到任何 --delay 值,就会使用默认的 1 与 -1s 进行运算。


Calc 字符串拼接


很多人在使用 CSS 的时候,会尝试字符串的拼接,像是这样:


<div style="--url: 'bsBD1I.png'"></div>
:root {
    --urlA: 'url(https://s1.ax1x.com/2022/03/07/';
    --urlB: ')';
}
div {
    width: 400px;
    height: 400px;
    background-image: calc(var(--urlA) + var(--url) + var(--urlB));
}


这里想利用 calc(var(--urlA) + var(--url) + var(--urlB)) 拼出完整的在 background-image 中可使用的 URL url(https://s1.ax1x.com/2022/03/07/bsBD1I.png)。

然而,这是不被允许的(无法实现的)。calc 的没有字符串拼接的能力。

唯一可能完成字符串拼接的是在元素的伪元素的 content 属性中。但是也不是利用 calc。


来看这样一个例子,这是错误的:


:root {
    --stringA: '123';
    --stringB: '456';
    --stringC: '789';
}
div::before {
    content: calc(var(--stringA) + var(--stringB) + var(--stringC));
}

此时,不需要 calc,直接使用自定义变量相加即可。


因此,正确的写法:


:root {
    --stringA: '123';
    --stringB: '456';
    --stringC: '789';
}
div::before {
    content: var(--stringA) + var(--stringB) + var(--stringC);
}


此时,内容可以正常展示:


05ffab5a681943818d848bf051416d33_tplv-k3u1fbpfcp-zoom-1.png

再强调一下,calc 的没有字符串拼接的能力,如下的使用方式都是无法被识别的错误语法:


.el::before {
  // 不支持字符串拼接
  content: calc("My " + "counter");
}
.el::before {
  // 更不支持字符串乘法
  content: calc("String Repeat 3 times" * 3);
}

min()、max()、clamp()



min()、max()、clamp() 适合放在一起讲。它们的作用彼此之间有所关联。

  • max():从一个逗号分隔的表达式列表中选择最大(正方向)的值作为属性的值
  • min():从一个逗号分隔的表达式列表中选择最小的值作为属性的值
  • clamp():把一个值限制在一个上限和下限之间,当这个值超过最小值和最大值的范围时,在最小值和最大值之间选择一个值使用


由于在现实中,有非常多元素的的属性不是一成不变的,而是会根据上下文、环境的变化而变化。


譬如这样一个布局:


<div class="container"></div>
.container {
    height: 100px;
    background: #000;
}


效果如下,.container 块它会随着屏幕的增大而增大,始终占据整个屏幕:

8831f81f1efb40ad82feea5b6e7151c1_tplv-k3u1fbpfcp-zoom-1.png


对于一个响应式的项目,我们肯定不希望它的宽度会一直变大,而是当达到一定的阈值时,宽度从相对单位变成了绝对单位,这种情况就适用于 min(),简单改造下代码:


.container {
    width: min(100%, 500px);
    height: 100px;
    background: #000;
}


容器的宽度值会在 width: 100% 与 width: 500px 之间做选择,选取相对小的那个。

在屏幕宽度不足 500px 时候,也就表现为 width: 100%,反之,则表现为 width: 500px:


d69f4dbd090d4a198763ce693ae581ba_tplv-k3u1fbpfcp-watermark.gif


同理,在类似的场景,我们也可以使用 max() 从多个值中,选取相对更大的值。


min()、max() 支持多个值的列表


min()、max() 支持多个值的列表,譬如 width: max(1px, 2px, 3px, 50px)。

当然,对于上述表达:


width: max(1px, 2px, 3px, 50px) 其实等于 width: 50px。因此,对于 min()、max() 的具体使用而言,最多应该只包含一个具体的绝对单位。否则,这样的像上述这种代码,虽然语法支持,但是任何情况下,计算值都是确定的,其实没有意义。


配合 calc


min()、max()、clamp() 都可以配合 calc 一起使用。


譬如:


div {
    width: max(50vw, calc(300px + 10%));
}

在这种情况下,calc 和相应包裹的括号可以省略,因此,上述代码又可以写成:


div {
    width: max(50vw, 300px + 10%);
}

基于 max、min 模拟 clamp


现在,有这样一种场景,如果,我们又需要限制最大值,也需要限制最小值,怎么办呢?

像是这样一个场景,**字体的大小,最小是 12px,随着屏幕的变大,逐渐变大,但是为了避免老人机现象(随着屏幕变大,无限制变大),我们还需要限制一个最大值 20px。

我们可以利用 vw 来实现给字体赋动态值,假设在移动端,设备宽度的 CSS 像素为 320px 时,页面的字体宽度最小为 12px,换算成 vw 即是 320 / 100 = 3.2,也就是 1vw 在 屏幕宽度为 320px 时候,表现为 3.2px,12px 约等于 3.75 vw。


同时,我们需要限制最大字体值为 20px,对应的 CSS 如下:


p {
    font-size: max(12px, min(3.75vw, 20px));
}
CSS 复制 全屏


看看效果:


f0a13f3454c1467387116fa10af6989e_tplv-k3u1fbpfcp-watermark.gif


通过 max()、min() 的配合使用,以及搭配一个相对单位 vw,我们成功的给字体设置了上下限,而在这个上下限之间实现了动态变化。


当然,上面核心的这一段 max(12px, min(3.75vw, 20px)) 看上去有点绕,因此,CSS 推出了 clamp() 简化这个语法,下面两个写法是等价的:


p {
    font-size: max(12px, min(3.75vw, 20px));
    // 等价于
    font-size: clamp(12px, 3.75vw, 20px);
}

clamp()


clamp() 函数的作用是把一个值限制在一个上限和下限之间,当这个值超过最小值和最大值的范围时,在最小值和最大值之间选择一个值使用。它接收三个参数:最小值、首选值、最大值。


有意思的是,clamp(MIN, VAL, MAX) 其实就是表示 max(MIN, min(VAL, MAX))。


使用 vw 配合 clamp 实现响应式布局



我们继续上面的话题。


在不久的过去,移动端的适配方面,使用更多的 rem 适配方案,可能会借助一些现成的库,类似于 flexible.js、hotcss.js 等库。rem 方案比较大的一个问题在于需要一段 JavaScript 响应视口变化,重设根元素的 font-size,并且,使用 rem 多少有点 hack 的感觉。


在现在,在移动端适配,我们更为推崇的是 vw 纯 CSS 方案,与 rem 方案类似,它的本质也是页面的等比例缩放。它的一个问题在于,如果仅仅使用 vw,随着屏幕的不断变大或者缩小,内容元素将会一直变大变小下去,这也导致了在大屏幕下,许多元素看着实在太大了!


因此,我们需要一种能够控制最大、最小阈值的方式,像是这样:



885a86261c2343e8879d142387d69de9_tplv-k3u1fbpfcp-zoom-1.png


此时,clamp 就能非常好的派上用场,还是我们上述的例子,这一段代码 font-size: clamp(12px, 3.75vw, 20px),就能将字体限制在 12px - 20px 的范围内。


因此,对于移动端页面而言,所有涉及长度的单位,我们都可以使用 vw 进行设置。而诸如字体、内外边距、宽度等不应该完全等比例缩放的,采用 clamp() 控制最大最小阈值。


Modern Fluid Typography Using CSS Clamp 一文中,对使用 clamp() 进行流式响应式布局还有更为深入的探讨,感兴趣的可以深入阅读。


总结一下,对于移动端页面,我们可以以 vw 配合 clamp() 的方式,完成整个移动端布局的适配。它的优势在于:


  • 没有额外 JavaScript 代码的引入,纯 CSS 解决方案
  • 能够很好地控制边界阈值,合理的进行缩放展示


反向响应式变化


还有一个技巧,利用 clamp() 配合负值,我们也可以反向操作,得到一种屏幕越大,字体越小的反向响应式效果:


p {
    font-size: clamp(20px, -5vw + 96px, 60px);
}


看看效果:

image.png


这个技巧挺有意思的,由于 -5vw + 96px 的计算值会随着屏幕的变小而增大,实现了一种反向的字体响应式变化。


总结


总结一下,合理运用 min()、max()、clamp(),是构建现代响应式布局的重点,我们可以告别传统的需要 JavaScript 辅助的一些方案,基于 CSS 这些数学函数即可完成所有的诉求。


一些进阶阅读非常好的文章:


目录
相关文章
|
6月前
|
Web App开发 前端开发 开发者
|
9月前
|
数据可视化 前端开发
漏刻有时数据大屏CSS样式表成长教程(2):九宫格图表背景自适应的解决方案
漏刻有时数据大屏CSS样式表成长教程(2):九宫格图表背景自适应的解决方案
86 1
|
9月前
|
前端开发 定位技术 容器
百度地图高级开发:上滑推拉菜单CSS解决方案
百度地图高级开发:上滑推拉菜单CSS解决方案
49 0
|
9月前
|
前端开发
layui使用table组件实现排序的CSS样式调整解决方案
layui使用table组件实现排序的CSS样式调整解决方案
132 0
|
9月前
|
前端开发
CSS按钮高亮的解决方案
CSS按钮高亮的解决方案
78 0
|
9月前
|
前端开发
Echarts实战案例代码(49):基于不支持立体漏斗图Funnel的HTML+CSS解决方案
Echarts实战案例代码(49):基于不支持立体漏斗图Funnel的HTML+CSS解决方案
102 0
|
9月前
|
前端开发 容器
Echarts实战案例代码(46):带渐变背景颜色的倾斜角度的图表的CSS样式表解决方案
Echarts实战案例代码(46):带渐变背景颜色的倾斜角度的图表的CSS样式表解决方案
83 0
|
9月前
|
前端开发 定位技术
百度地图标注提示框CSS气泡对话框实现属性解决方案
百度地图标注提示框CSS气泡对话框实现属性解决方案
79 0
|
9月前
|
前端开发 JavaScript
CSS的终结解决方案是什么?
CSS的终结解决方案是什么?
|
编解码 前端开发 iOS开发
CSS 数学函数之calc、clamp、min、max
回想过去,CSS 需要兼容各种版本的浏览器,那种在效果和可用之间痛苦选择的经历记忆犹新。现在的 CSS 能够做很多事情,而对于浏览器的兼容性只需考虑主流的,并且大部分主流的浏览器都支持最新 CSS 特性。本文来总结一下CSS中数学函数之min、max、calc、clamp。
253 0