Clamp()、Max() 和 Min() CSS 函数的用例

前端Q

共 5000字,需浏览 10分钟

 · 2022-10-21

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群


英文 | https://ishadeed.com/article/use-cases-css-comparison-functions/

2020 年 4 月开始支持 CSS 比较函数,当时我写了一篇介绍关于它们的文章。我喜欢使用所有这些,但我最喜欢的一个是clamp(),它是我最常用的一个。

在本文中,我将探讨一些比较函数的用例,并详细解释每一个用例,大多数情况下,用例将是关于将它们用于流动尺寸以外的情况,因为这是最流行的用例,我将把它留到最后。
如果你不了解比较函数,那也没有关系,现在我们一起来学习。
Clamp()、Max() 和 Min() CSS 函数的用例
流体尺寸和定位
在此示例中,我们有一个带有手机的部分,以及位于顶部的两个图像。最初,它将如下图所示:

当容器的宽度变小时,我们希望缩小图像的大小以适应可用空间。我们可以通过使用宽度或高度的百分比值(例如:宽度:20%)来做到这一点,但这并没有给我们太多的控制权。
我们希望能够有一个流体大小,它同时尊重最小值和最大值,这就是clamp来救援的地方!
CSS:
.section-image {  width: clamp(70px, 80px + 15%, 180px);}

通过设置最小、首选和最大宽度,图像将根据其容器宽度缩小或增长,这是由于使用了固定值和百分比 80px + 15% 的混合。

演示地址:https://codepen.io/shadeed/pen/qBYPdOq?editors=1100

装饰元素

如果你需要在部分项目中添加装饰元素,大多数时候,元素需要响应,并且可能需要根据视口大小进行不同的定位,你会怎么做?

如下示例效果:

两侧有两个装饰元素。在移动设备上,它们会占用太多空间,因此我们只想展示其中的一小部分。

为了解决这个问题,我们可以在移动设备上使用媒体查询来控制它们。

CSS:

.decorative--1 {  left: 0;}
.decorative--2 { right: 0;}
@media (max-width: 600px) { .decorative--1 { left: -8rem; }
.decorative--2 { right: -8rem; }}

虽然这可行,但我们可以使用带有 CSS clamp() 函数的无媒体查询解决方案。

CSS:

@media (max-width: 600px) {  .decorative--1 {    left: clamp(-8rem, -10.909rem + 14.55vw, 0rem);  }
.decorative--2 { right: clamp(-8rem, -10.909rem + 14.55vw, 0rem); }}

让我剖析一下上面的 CSS,让你更容易理解:

  • 我们想要的是设置最小左偏移为-8rem,最大值为0rem。

  • 有了这个,我们把它留给 CSS clamp() 来决定首选值并尊重我们设置的最小值和最大值。

我用这个计算器(https://min-max-calculator.9elements.com/)得到了上面的 clamp() 数字。

演示地址:https://codepen.io/shadeed/pen/LYmzVZW?editors=1100

流体英雄高度

与前面的示例相关,英雄部分的高度可以根据视口大小而不同。因此,我们倾向于通过媒体查询或使用视口单元来改变它。

CSS:

.hero {  min-height: 250px;}
@media (min-width: 800px) { .hero { min-height: 500px; }}

我们可以混合使用固定值和视口单位,但我们需要注意不要在较大的视口上设置很大的高度,然后,我们需要设置一个最大高度。

CSS:

.hero {  min-height: calc(350px + 20vh);}
@media (min-width: 2000px) { .hero { min-height: 600px; }}

使用 CSS clamp(),我们可以只用一个 CSS 声明来设置最小、首选和最大高度。

.hero {  min-height: clamp(250px, 50vmax, 500px);}

调整屏幕大小时,你会注意到高度会根据视口宽度逐渐变化。在上面的示例中,50vmax 表示“视口最大尺寸的 50%。

演示地址:https://codepen.io/shadeed/pen/LYmzVZW?editors=1100

加载条

这个例子的灵感来自 Andy Bell 的一条推文,我真的很喜欢在这个用例中使用 CSS clamp()!

条形按钮应该从左到右进行动画处理,反之亦然。在 CSS 中,按钮可以绝对定位在左侧。

CSS:

.loading-thumb {  left: 0%;}

要将按钮放在最右边,我们可以使用 left: 100% 但这会带来一个问题,按钮将从装载杆容器中吹出。

CSS:

.loading-thumb {  left: 100%;}

这是意料之中的,因为在这种情况下 100% 从拇指末端开始,因此将其推出。

我们可以使用 CSS calc() 减去按钮宽度,它会起作用,但这不是 100% 灵活的。

CSS:

.loading-thumb {  /* 40px represents the thumb width. */  left: calc(100% - 40px);}

让我们探索如何使用 CSS 变量和比较函数来改进 CSS。

CSS:

.loading-thumb {  --loading: 0%;  --loading-thumb-width: 40px;  position: absolute;  top: 4px;  left: clamp(    0%,    var(--loading),    var(--loading) - var(--loading-thumb-width)  );  width: var(--loading-thumb-width);  height: 16px;}

以下是上述 CSS 的工作原理:

  • 首先,我们将最小值设置为 0%。

  • 首选值是 --loading CSS 变量的当前值。

  • 最大值表示当前加载减去按钮宽度。

CSS clamp() 在这里为我们提供了这个组件的三个不同的统计信息,我个人喜欢这个解决方案!

不仅如此,我们还可以为不同的设计扩展相同的概念。考虑下图:

当前进度值在它上面有一个小句柄,当值为 100% 时,我们需要宽度来尊重它。

如下图所示,圆圈必须在最右侧结束,如果我们不注意这一点,它最终会吹出手柄宽度的一半(参见带有红色标志的第二行)。

在这种情况下,我们可以使用 CSS clamp() 函数。

CSS:

.loading-progress {  width: clamp(10px, var(--loading), var(--loading) - 10px);}

最小值等于半圆宽度,优选值是当前加载百分比,最大值是半圆减去当前百分比的结果。

演示地址:https://codepen.io/shadeed/pen/rNvGVOa?editors=0100

动态线分隔符

今年早些时候,我写了一篇关于我正在开发的 UI 的有趣 CSS 解决方案的文章。

考虑下图,我们在两个部分之间有一个行分隔符。

在移动设备上,该分隔符应变为水平,如下所示。

我的解决方案是使用边框和弹性框,这个方法是带有边框的伪元素可以扩展以填充垂直和水平状态的可用空间。

CSS:

.section {  display: flex;  flex-direction: column;  gap: 1rem;}
.section:before { content: ""; border: 1px solid #d3d3d3; align-self: stretch;}
@media (min-width: 700px) { .section { align-items: center; flex-direction: row; }}

我们甚至可以通过使用 CSS clamp 来实现,Temani Afif 提出了一个根本不需要媒体查询的解决方案。

CSS:

.section {  --breakpoint: 400px;  display: flex;  flex-wrap: wrap;}
.section:before { content: ""; border: 2px solid lightgrey; width: clamp(0px, (var(--breakpoint) - 100%) * 999, 100%);}

让我们剖析一下上面的 CSS:

  • 0px:最小值,用于垂直分隔符。它为零,因为我们使用的是 CSS 边框。

  • (var(--breakpoint) - 100%) * 999 根据视口宽度在 0px 或 100% 之间切换。

条件边界半径

大约一年前,我在 Facebook 提要 CSS 中发现了一个巧妙的 CSS 技巧。它是关于使用 CSS max() 比较函数根据视口宽度将卡片的半径从 0px 切换到 8px。

CSS:

.card {  border-radius: max(    0px,    min(8px, calc((100vw - 4px - 100%) * 9999))  );}

让我们详细了解一下上面的 CSS。

现在我们来剖析一下上面的 CSS:

  • 我们有一个 max() 函数,用于比较 0px 和 min() 的计算值,它将选择较大的值。

  • min() 函数在 8px 和 calc((100vw - 4px - 100%) * 9999) 的计算值之间进行比较,这将导致非常大的正数或负数。

  • 9999 是一个很大的数字,强制该值为 0px 或 8px。

有了上面的内容,当卡片占据整个视口宽度时,它的半径为零,或者在更大的屏幕上为 8px。

CSS 文章标题

在构建CSS 文章标题时,我需要一种方法来为内容添加动态填充,同时,在较小的视口上保持最小值。

这个想法是文章标题不包含在包装元素中,因此我们需要一种方法来模拟内容实际上被包装并与下面的内容对齐。

为此,我们需要一种在 CSS 中使用以下公式的方法:

动态填充 = (视口宽度 - 包装宽度) / 2

感谢 CSS max() 函数,我们可以添加最小填充,以及在需要时切换到动态填充的方法。

CSS:

:root {  --wrapper-width: 1100px;  --wrapper-padding: 16px;  --space: max(    1rem,    calc(      (          100vw - calc(var(--wrapper-width) - var(--wrapper-padding) *                2)        ) / 2    )  );}
.article-header { padding-left: var(--space);}

这个想法是我们需要最小填充为 1rem,然后,它将根据视口宽度动态变化。

间距

有时,我们可能需要根据视口宽度更改组件或网格的间距。不带 CSS 比较功能!我们只需要设置一次。

.wrapper {  display: grid;  grid-template-columns: repeat(3, 1fr);  grid-gap: min(2vmax, 32px);}

关于间距的知识,我们后面将会详细介绍,今天的内容就先分享到这里,感谢你的阅读。

往期推荐


5 种瀑布流场景的实现原理解析
纯前端实现「羊了个羊」小游戏
你的图片加载,一点都不酷炫!不信 You Look Look

最后


  • 欢迎加我微信,拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

点个在看支持我吧

浏览 28
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报