CSS数学函数详细使用教程:calc, clamp, min, max

430 阅读12分钟

目前在CSS中有四个支持良好的数学函数。我发现它们中的每一个在我的日常工作中都非常有用。这些CSS函数的使用方式可能出乎意料,比如在梯度和颜色函数中使用,以及与CSS自定义属性结合使用。我们将学习每个函数的语法,观看其功能的基本演示,并探索实际的使用案例。

跳到

calc()#

calc() 的实际用途:执行基本的数学运算,具有在单位类型之间插值的能力(例如:remvw )。

这个数学函数在我们探索的四个函数中具有最长的跨浏览器支持。它有广泛的用途,任何时候你都想在你的样式中进行客户端数学运算。

例如,你可能想让某些东西占据大部分视口的高度,除了导航的高度。为此,你可以混合单位来传递一个相对的vh (视图高度)单位和一个绝对的像素单位。

.content {  height: calc(100vh - 60px);}

随着视口大小的调整或用户在更大或更小的设备上访问,100vh 的值将动态更新,因此计算也将动态更新。

calc() 的好处是允许你避免硬编码一系列神奇的数字,或添加一个JavaScript解决方案来计算所需的值,以应用它作为一个内联样式。

使用calc() ,生成调色板#

我们可以通过传入CSS自定义属性来扩展calc() 的功能。

一个非常有用的例子是使用hsl() (代表色调、饱和度和亮度)创建一个一致的调色板。给出饱和度、亮度和起始色调的值,我们可以计算出互补的值来建立一个完整的调色板。由于饱和度和亮度值之间的共性,调色板会感觉很有凝聚力。

"使用calc()创建HSL调色板 "的CSS

.colors {  --base-hue: 140;  --saturation: 95%;  --lightness: 80%;  --rotation: 60;  color: #222;  text-align: center;}.color {  padding: 0.25rem;  background-color: hsl(var(--hue), var(--saturation), var(--lightness));}.color1 {  --hue: calc(var(--base-hue));}.color2 {  --hue: calc(var(--base-hue) + var(--rotation));}.color3 {  --hue: calc(var(--base-hue) + var(--rotation) * 2);}

.color-397 { --base-hue: 140; --saturation: 95%; --lightness: 80%; --rotation:60; 颜色。#222; text-align: center; } .color-397 { padding:0.25rem; background-color: hsl(var(-hue), var(-saturation), var(-lightness)); } .color1-397 { --色调: calc(var(-base-hue)); } .color2-397 { --色调: calc(var(-base-hue) + var(--rotation)) ; } .color3-397 { --色调: calc(var(-base-hue) + var(--rotation) * 2) ; }

  • 颜色1
  • 颜色2
  • 颜色3

clamp()#

clamp() 的实际目的:在可接受的数值范围内设置界限。

clamp() 函数需要三个值,而且顺序很重要。第一个是你范围内的最低值,中间是你的理想值,第三个是你范围内的最高值。

你可能已经遇到过使用clamp() 的一个领域,那就是流体排版。其基本概念是,font-size 的值可以根据视口的大小而流动调整。这样做的目的是为了防止大标题触发溢出,或占用太多的视口。

一个非常基本的流体h1 样式的定义。

h1 {  font-size: clamp(1.75rem, 4vw + 1rem, 3rem);}

你可以在《现代CSS》第12集中阅读更多关于生成流体类型的内容。

使用clamp()#的相对响应填充。

另一个例子是我在SmolCSS中关于响应式填充的演示。使用百分比填充的有趣之处在于,它是相对于元素的宽度而言的。这意味着它有点像一个相对于容器的单位,我们可以使用类似于你可能认为的vw

SmolCSS的例子使用了以下的padding定义,其中padding将相对于元素的宽度增长和缩小。它永远不会小于1rem ,也不会大于3rem

.element {  padding: 1.5rem clamp(1rem, 5%, 3rem);}

你可能已经意识到,这又消除了一些你以前可能会伸手的媒体查询的场景。你可以为响应式过渡设置合理的准则,而不是对这个间距进行微观管理,或者担心严格遵守一个像素斜率(例如8、12、24、36)。

与媒体查询相比,这里最重要的好处是,由于这个填充定义是相对于元素的,当元素在页面上有更多的空间时,它就会变大,而如果,例如,它被放置在一个狭窄的列中,就会变小。这将需要与基于媒体查询的实用类进行大量的协调!

min()#

min() 的实际目的:以包含元素的响应性上下文的方式为最大允许值设定界限。

这是正确的--尽管是min() 函数,其结果是提供的值将作为属性的_最大_允许值。

给定width: min(80ch, 100vw) ,结果是在一个较大的视口上,80ch 将被选中,因为它是两个选项中较小的值,但它却_像_一个基于上下文可用空间的最大值。一旦视口缩小,100vw 将被使用,因为它被计算为_比_ 80ch,但它实际上是为元素的宽度提供了一个_最大_边界。

现代CSS.container#

刚刚提供的例子是我喜欢的定义.container 的方式,只是做了一个小小的调整。min() 函数允许嵌套的基本数学运算,这意味着我们可以翻转到减去一些空间作为定义左右填充的交换,如下所示。

.container {  width: min(80ch, 100vw - 2rem);}

在较大的视口上,该元素可以增长到_最大的_ 80ch ,而一旦视口缩小到该宽度以下,它将被允许增长到100vw - 2rem 。这个定义有效地在元素的两边产生了1rem 的 "padding"。

在这个例子中,你也可以换成100% ,而不是vw ,以使元素的宽度在_父容器_中得到响应,就像这个演示中使用的那样。

现代CSS .container类 "的CSS

.container {  width: min(40ch, 100% - 2rem);  margin-right: auto;  margin-left: auto;  outline: 1px dashed;}

.container-521 { width: min(40ch, 100% - 2rem); margin-right: auto; margin-left: auto; padding:1rem; color:#222; 轮廓: 1px 虚线; }

Lorem ipsum dolor sit, amet consectetur adipisicing elit.因此,一个quam labore inventore iste eligendi, quasi velit, qui repellendus voluptatem temporibus nisi.Pariatur nesciunt at dolorum, cumque illum maiores animi?

快速提示ch 单位等于应用时给定的所有当前font 属性的0 字符的宽度。这使得它成为一个很好的选择,例如,为了获得更好的阅读体验,它可以近似于行的长度。

有什么好处?_无需_媒体查询的响应式尺寸!这似乎是这些函数的一个共同主题 😉

min() 函数是我最常用的数学函数。让我们来看看一些更神奇的实际场景的升级。

使用min()#的响应式元素大小

任何时候你想响应地调整一个元素的大小,min() 都是一个不错的选择。例如,我在Modern CSS第26集探讨了使用min() 来控制评论线程中头像的大小。

在头像的例子中,我们最终应用了_三个_不同单位的值:min(64px, 15%, 10vw) 。另一种解读方式是,头像的大小在任何时候都不会超过其中一个值,浏览器会选择_最小的_计算值。

这个定义意味着头像永远不会大于64px 。特别是在放大的情况下,10vw ,有助于使尺寸感觉更相对。而15% 则有助于保持与元素的相对大小,在应用10vw 之前,可能会有一个更有视觉吸引力的结果。

你希望在你的收件箱中收到CSS技巧吗? 加入我的时事通讯,获取文章更新、CSS技巧和前端资源吧

在其他属性中使用min() #

CSS数学函数可以在大多数允许使用数字值的属性中使用。有一个独特的地方可以使用它们,就是在background-size

为什么?也许你要提供一个由背景颜色和图像组成的分层效果。而不是使用cover 大小值,那会使图像填满空间,你想为图像的增长设置上限。这是一个引入min() 的完美地方。

考虑下面的例子,min() 被用来确保图像不超过600px ,同时通过设置100% ,允许图像与元素一起向下响应。换句话说,它将增长_到_ 600px ,当元素的宽度小于600px ,它就会调整自己的大小以配合元素的宽度。

"现代CSS .container类 "的CSS

.background-image {  background: #1F1B1C url(https://source.unsplash.com/RapCPd_mJTU/800x800) no-repeat center;  background-size: min(600px, 100%);}

.background-image-877 { display: grid; place-items: center; grid-template-areas:"background"; background:#1F1B1C url(source.unsplash.com/RapCPd\_mJT…) no-repeat center; background-size: min(600px, 100%); box-shadow: inset 600px 600px rgba(0, 0, 0, 0.45); } .background-image-877 p { display: grid; place-content: center; grid-area: background; width: min(600px, 100%); outline: 1px dashed; min-height: 8rem; color: white; padding:1rem; }

Lorem ipsum dolor sit, amet consectetur adipisicing elit.意思是说,如果你的工作是为你自己而做的,那么你的工作就是为你自己而做的,而不是为你自己而做的。

max()#

max() 的实际目的:以包含元素的响应环境的方式,为最小允许值设定界限。

是的,max()min() 正好相反 !所以现在我们正在为_最小_允许值设置定义。让我们直接进入例子!

使用max()#的上下文边距

在学习了《网络内容可及性指南》(WCAG)关于回流的成功标准1.4.10之后,其中规定用户应该能够使用缩放功能将你的网站放大到400%,我注意到在这种情况下,像素和雷姆成为一个不合格的单位。

鉴于桌面尺寸为1280px,缩放比例为400%,你的内容相当于一个设备的320px。然而--相对于手机而言--方向仍然是横向的。这种尺寸的视口意味着阅读和执行操作的区域大大减少。此外,在手机上看起来合适的尺寸,在放大的窗口中观看时就会变得很大。

幸运的是,max() 给我们提供了一种方法,特别是可以更优雅地处理边距。在我的个人工作中,我避免使用像素值,通常喜欢用rem ,用于较小的空间。但对于旨在分隔内容部分的较大空间,我使用以下方法,它允许高的视口有相对增长,而对于短的视口则减少距离,这也适用于放大的视口。

.element + .element {  margin-top: max(8vh, 2rem);}

在较高的视口上,将使用8vh ,而在较小或放大的视口上,将使用2rem 。我鼓励你尝试这个方法,并花一些时间在不同的视口、设备、以及放大或不放大你的布局时进行测试。这个技术是一个小的升级,可以为终端用户带来显著的变化。

在《现代CSS》第27集中,我们将回顾这一场景的扩展示例,并学习更多关于回流的知识

max()#防止iOS中输入的浏览器缩放

你有没有遇到过在iOS上聚焦表单输入后浏览器强制缩放的情况?这种情况会发生在任何字体大小小于16px 的输入上。

这就是修复方法,最初是在Modern CSS第21集关于自定义表单输入样式的内容中链接的,这个简单的解决方案完全归功于Dan Burzo

input {  font-size: max(16px, 1rem);}

其中1rem 可以用一个Sass变量或一个CSS自定义属性来代替。这种对max() 的使用确保了无论提供什么其他的值,font-size _至少_是16px ,从而防止浏览器强制缩放。

使用max()#的相对焦点轮廓

我最新添加的CSS重置使用min() ,为焦点轮廓应用相对大小。

这是一个缩小的片段,但通过使用max() ,我们确保了_最小的_轮廓尺寸为2px ,同时通过使用font-relativeem 值,允许它相对于元素_增长_。

a {  --outline-size: max(2px, 0.08em);  --outline-style: solid;  --outline-color: currentColor;}a:focus {  outline: var(--outline-size) var(--outline-style) var(--outline-color);  outline-offset: var(--outline-size);}

使用max()#的可访问目标尺寸

术语 "目标尺寸 "来自WCAG成功标准(SC)2.5.5,其中 "目标 "指的是将收到指针事件(例如,鼠标点击或触摸点击)的区域。在即将发布的WCAG 2.2中,SC 2.5.5现在是 "增强 "版,它的最小尺寸为44px

对于这个准则,可以考虑只使用图标的按钮,或者我们前面的例子中链接到个人资料的头像。或者是一个双行动按钮,其中的下拉箭头是一个独立于主要按钮控制的行动。

在这些情况下,我们可以使用max() ,类似于我们提供护栏来防止输入缩放的情况。我们将设置44px ,作为max() 内的一个值,这样_最低限度_,这就是该元素的尺寸。

.icon-button {  width: max(44px, 2em);  height: max(44px, 2em);}

需要注意的是,这个标准还考虑了元素周围的空间,如果与元素的实际尺寸相结合,_至少_是44px,那么这个标准就成功通过。就像所有这些技术一样,一定要用你的实际产品和真实的用户来进行测试!

使用max() 作为CSSaspect-ratio#的回避。

我使用max() 的另一种方式是在使用aspect-ratio 时设置一个图像高度,以使那些还不支持该属性的浏览器能够获得可接受的体验。

你可以看到下面的样本完全用于SmolCSS演示中的可组合卡片组件

img {  /* Fallback for `aspect-ratio` of defining a height */  height: max(18vh, 12rem);  object-fit: cover;  width: 100%;}/* When supported, use `aspect-ratio` */@supports (aspect-ratio: 1) {  img {    aspect-ratio: var(--img-ratio);    height: auto;  }}

把它放在一起#

这个最后的演示展示了一个应用多个CSS数学函数的例子,以便在多个属性中实现响应式的大小调整。请注意演示代码旁边的注释。

作者:Stephanie Eckles (@5t3ph)

关于使用这些CSS数学函数和其他现代CSS功能的更多例子,请查看我在YouTube上的CSS Cafe演讲