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

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

在 CSS 中,其实存在各种各样的函数。具体分为:



本文,将具体介绍其中的 CSS 数学函数(Math functions)中,已经被浏览器大规模支持的 4 个:


  • calc()
  • min()
  • max()
  • clamp()


为什么说是被浏览器大规模支持的?因为除了这 4 个目前已经得到大规模支持的数学函数外,其实规范 CSS Values and Units Module Level 4 已经定义了诸如三角函数相关 sin()、cos()、tan() 等,指数函数相关 pow()、sqrt() 等等数学函数,只是目前都处于实验室阶段,还没有浏览器支持它们,需要给时间一点时间。


Calc()



calc() 此 CSS 函数允许在声明 CSS 属性值时执行一些计算。


语法类似于


{
    width: calc(100% - 80px);
}


一些需要注意的点:

  • + 和 - 运算符的两边必须要有空白字符。比如,calc(50% -8px) 会被解析成为一个无效的表达式,必须写成calc(8px + -50%)
  • * 和 / 这两个运算符前后不需要空白字符,但如果考虑到统一性,仍然推荐加上空白符
  • 用 0 作除数会使 HTML 解析器抛出异常
  • 涉及自动布局和固定布局的表格中的表列、表列组、表行、表行组和表单元格的宽度和高度百分比的数学表达式,auto 可视为已指定。
  • calc() 函数支持嵌套,但支持的方式是:把被嵌套的 calc() 函数全当成普通的括号。(所以,函数内直接用括号就好了。)
  • calc() 支持与 CSS 变量混合使用


看一个最常见的例子,页面结构如下:


<div class="g-container">
    <div class="g-content">Content</div>
    <div class="g-footer">Footer</div>
</div>


页面的 g-footer 高为 80px,我们希望不管页面多长,g-content 部分都可以占满剩余空间,像是这样:


3ddacd4b794940779bce7956c4be0d99_tplv-k3u1fbpfcp-zoom-1.png


这种布局使用 flex 的弹性布局可以轻松实现,当然,也可以使用 calc() 实现:


.g-container {
    height: 100vh;
}
.g-content {
    height: calc(100vh - 80px);
}
.g-footer {
    height: 80px;
}


下面罗列一些 Calc() 的进阶技巧。


Calc 中的加减法与乘除法的差异


注意,calc() 中的加减法与乘除法的差异:

{
    font-size: calc(1rem + 10px);
    width: calc(100px + 10%);
}


可以看到,加减法两边的操作数都是需要单位的,而乘除法,需要一个无单位数,仅仅表示一个倍率:


{
    width: calc(100% / 7);
    animation-delay: calc(1s * 3);
}

Calc 的嵌套


calc() 函数是可以嵌套使用的,像是这样:


{
  width: calc(100vw - calc(100% - 64px));
}

此时,内部的 calc() 函数可以退化写成一个括号即可 (),所以上述代码等价于:

{
  width: calc(100vw - (100% - 64px));
}

也就是嵌套内的 calc(),calc 几个函数字符可以省略。


Calc 内不同单位的混合运算


calc() 支持不同单位的混合运算,对于长度,只要是属于长度相关的单位都可以进行混合运算,包含这些:


  • px
  • %
  • em
  • rem
  • in
  • mm
  • cm
  • pt
  • pc
  • ex
  • ch
  • vh
  • vw
  • vmin
  • vmax


这里有一个有意思的点,运算肯定是消耗性能的,早年间,有这样一段 CSS 代码,可以直接让 Chrome 浏览器崩溃 Crash:

<div></div>

CSS 样式如下:


div {
  --initial-level-0: calc(1vh + 1% + 1px + 1em + 1vw + 1cm);
  --level-1: calc(var(--initial-level-0) + var(--initial-level-0));
  --level-2: calc(var(--level-1) + var(--level-1));
  --level-3: calc(var(--level-2) + var(--level-2));
  --level-4: calc(var(--level-3) + var(--level-3));
  --level-5: calc(var(--level-4) + var(--level-4));
  --level-6: calc(var(--level-5) + var(--level-5));
  --level-7: calc(var(--level-6) + var(--level-6));
  --level-8: calc(var(--level-7) + var(--level-7));
  --level-9: calc(var(--level-8) + var(--level-8));
  --level-10: calc(var(--level-9) + var(--level-9));
  --level-11: calc(var(--level-10) + var(--level-10));
  --level-12: calc(var(--level-11) + var(--level-11));
  --level-13: calc(var(--level-12) + var(--level-12));
  --level-14: calc(var(--level-13) + var(--level-13));
  --level-15: calc(var(--level-14) + var(--level-14));
  --level-16: calc(var(--level-15) + var(--level-15));
  --level-17: calc(var(--level-16) + var(--level-16));
  --level-18: calc(var(--level-17) + var(--level-17));
  --level-19: calc(var(--level-18) + var(--level-18));
  --level-20: calc(var(--level-19) + var(--level-19));
  --level-21: calc(var(--level-20) + var(--level-20));
  --level-22: calc(var(--level-21) + var(--level-21));
  --level-23: calc(var(--level-22) + var(--level-22));
  --level-24: calc(var(--level-23) + var(--level-23));
  --level-25: calc(var(--level-24) + var(--level-24));
  --level-26: calc(var(--level-25) + var(--level-25));
  --level-27: calc(var(--level-26) + var(--level-26));
  --level-28: calc(var(--level-27) + var(--level-27));
  --level-29: calc(var(--level-28) + var(--level-28));
  --level-30: calc(var(--level-29) + var(--level-29));
  --level-final: calc(var(--level-30) + 1px);
    border-width: var(--level-final);                                 
    border-style: solid;
}

可以看到,从 --level-1 到 --level-30,每次的运算量都是成倍的增长,最终到 --level-final 变量,展开将有 2^30 = 1073741824 个 --initial-level-0 表达式的内容。

并且,每个 --initial-level-0 表达式的内容 -- calc(1vh + 1% + 1px + 1em + 1vw + 1cm),在浏览器解析的时候,也已经足够复杂。


混合在一起,就导致了浏览器的 BOOM(Chrome 70之前的版本),为了能看到效果,我们将上述样式赋给某个元素被 hover 的时候,得到如下效果:

b6b9df03aff04842b72655ae6daffc25_tplv-k3u1fbpfcp-zoom-1.gif



当然,这个 BUG 目前已经被修复了,我们也可以通过这个小 DEMO 了解到,一是 calc 是可以进行不同单位的混合运算的,另外一个就是注意具体使用的时候如果计算量巨大,可能会导致性能上较大的消耗。


当然,不要将长度单位和非长度单位混合使用,像是这样:


{
    animation-delay: calc(1s + 1px);
}


Calc 搭配 CSS 自定义变量使用


calc() 函数非常重要的一个特性就是能够搭配 CSS 自定义以及 CSS @property 变量一起使用。

最简单的一个 DEMO:


:root {
    --width: 10px;
}
div {
    width: calc(var(--width));
}


当然,这样看上去,根本看不出这样的写法的作用,好像没有什么意义。实际应用场景中,会比上述的 DEMO 要稍微复杂一些。


假设我们要实现这样一个 loading 动画效果,一开始只有 3 个球:

5960956ff9d14474b68e55ce533394e7_tplv-k3u1fbpfcp-zoom-1.gif


可能的写法是这样,我们给 3 个球都添加同一个旋转动画,然后分别控制他们的 animation-delay


<div class="g-container">
    <div class="g-item"></div>
    <div class="g-item"></div>
    <div class="g-item"></div>
</div>
.item:nth-child(1) {
    animation: rotate 3s infinite linear;
}
.item:nth-child(2) {
    animation: rotate 3s infinite -1s linear;
}
.item:nth-child(3) {
    animation: rotate 3s infinite -2s linear;
}


如果有一天,这个动画需要扩展成 5 个球的话,像是这样:

f12729f0510d4b268ecf2ccdfd1fd3fa_tplv-k3u1fbpfcp-zoom-1.gif


我们就不得已,得去既添加 HTML,又修改 CSS。而如果借助 Calc 和 CSS 变量,这个场景就可以稍微简化一下。


假设只有 3 个球:


<div class="g-container">
    <div class="g-item" style="--delay: 0"></div>
    <div class="g-item" style="--delay: 1"></div>
    <div class="g-item" style="--delay: 2"></div>
</div>

我们通过 HTML 的 Style 标签,传入 --delay 变量,在 CSS 中直接使用它们:


.g-item {
    animation: rotate 3s infinite linear;
    animation-delay: calc(var(--delay) * -1s);
}
@keyframes rotate {
    to {
        transform: rotate(360deg);
    }
}

而当动画修改成 5 个球时,我们就不需要修改 CSS,直接修改 HTML 即可,像是这样:


<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" style="--delay: 1.2"></div>
    <div class="g-item" style="--delay: 1.8"></div>
    <div class="g-item" style="--delay: 2.4"></div>
</div>

核心的 CSS 还是这一句,不需要做任何修改:


{
    animation-delay: calc(var(--delay) * -1s);
}


完整的 DEMO,你可以戳这里:CodePen Demo -- Calc & CSS Variable Demo

目录
相关文章
|
Web App开发 前端开发 开发者
|
1月前
|
前端开发 JavaScript
如何在 CSS 变量中使用函数?
【10月更文挑战第28天】虽然CSS变量本身不能像传统编程语言中的函数那样直接进行复杂的运算和逻辑处理,但通过CSS预处理器、`calc()` 函数以及与JavaScript的结合,可以在很大程度上实现类似函数的功能,提高CSS样式的灵活性和可维护性,满足各种不同的页面设计和交互需求。
|
2月前
|
安全 前端开发 开发者
CSS3 中 calc()、constant() 和 env() 函数的使用指南
在现代网页设计中,CSS3 的 calc()、constant() 和 env() 函数为开发者提供了强大的工具,帮助实现灵活和响应式的布局。本文将深入探讨这三个函数的定义、用法以及最佳实践,特别是如何利用 calc() 进行动态计算、constant() 的历史背景,以及 env() 在处理设备安全区域中的应用。通过本文,读者将能够更好地理解并运用这些函数,提升网页设计的灵活性与用户体验。
60 0
|
5月前
|
前端开发
css【详解】cubic-bezier()函数
css【详解】cubic-bezier()函数
104 2
|
5月前
|
前端开发
css【详解】steps()函数
css【详解】steps()函数
32 1
|
6月前
|
前端开发 文件存储 Python
【已解决】Flask当中render_template函数使用过程当中css文件无法正常渲染
【已解决】Flask当中render_template函数使用过程当中css文件无法正常渲染
|
5月前
|
前端开发 容器
css 【详解】—— 图片底部留有间隙(含解决方案)
css 【详解】—— 图片底部留有间隙(含解决方案)
135 0
|
7月前
|
前端开发 UED 开发者
【专栏】探讨了CSS3动画卡顿的原因,包括复杂动画效果、过多元素参与、低效代码结构和硬件资源限制,并提出优化措施
【4月更文挑战第29天】本文探讨了CSS3动画卡顿的原因,包括复杂动画效果、过多元素参与、低效代码结构和硬件资源限制,并提出优化措施:简化动画路径、控制元素数量、优化代码结构、利用硬件加速及性能监测。通过实际案例展示了优化效果,强调了性能优化对提升用户体验的重要性。在开发中,应持续关注并优化动画性能,以适应网页应用的需求。
386 1
|
7月前
|
移动开发 JavaScript 前端开发
原生JavaScript+CSS实现计算器(简单的介绍一下eval函数)
原生JavaScript+CSS实现计算器(简单的介绍一下eval函数)
68 0
|
数据可视化 前端开发
漏刻有时数据大屏CSS样式表成长教程(2):九宫格图表背景自适应的解决方案
漏刻有时数据大屏CSS样式表成长教程(2):九宫格图表背景自适应的解决方案
138 1