Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一文学会使用 CSS 中的 min(), max(), clamp() 以及它们的使用场景 #258

Open
husky-dot opened this issue Aug 6, 2020 · 0 comments

Comments

@husky-dot
Copy link
Owner

作者:Ahmad shaded
译者:前端小智
来源:sitepoint

点赞再看,微信搜索**【大迁世界】**关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。

2020年4月8日Firefox浏览器支持了 CSS 比较函数min()max()clamp()),这意味着现在所有主流浏览器都支持它们。 这些CSS函数最大的作用就是可以为我们提供动态布局和更灵活设计组件方法。

简单的这些元素主要用来设置元素尺寸,如容器大小,字体大小,内距,外距等等 。在这篇文章中,我将用一些示例和大家一起来探讨这几个函数在实际中的使用,希望能更好的帮助大家理解它们。

兼容性

minmax 的支持情况:

clamp()的支持情况:

CSS 比较函数

根据CSS规范,比较函数是关于比较多个值并取其一的操作,我们来研究一下函数。

Min() 函数

min() 函数支持一个或多个表达式,每个表达式之间使用逗号分隔,然后以最小的表达式的值作为返回值,我们可以使用min()为元素设置最大值。

考虑下面的例子,我们希望元素的最大宽度为500px

.element {
    width: min(50%, 500px);
}

浏览器需要在(50%,500px) 取一个最小值,因为有个百分比,所以最终结果取决于视口宽度。如果50%的计算值大于500px,那么就取 500px

否则,如果50%计算值小于500px,则50%将用作宽度的值,假设视口的宽度是 900px, 最终元素的宽度为 900px x 50% = 450px

下面是一个交互的动画为了让大家更好的理解:

事例源码:https://codepen.io/shadeed/debug/f5e338c8a1c7cd29e382c72a5eb37e48/auth

Max() 函数

max()函数和min()函数语法类似,区别在于max()函数返回的是最大值,min()函数返回的是最小值。同样,我们可以使用man()为元素设置最小值。

考虑下面的例子,我们希望元素的最小宽度为500px

.element {
    width: max(50%, 500px);
}

浏览器需要在(50%,500px) 取一个最大值,因为有个百分比,所以最终结果取决于视口宽度。如果50%的计算值小于500px,那么就取 500px

否则,如果50%计算值大于500px,则50%将用作宽度的值,假设视口的宽度是 1150px, 最终元素的宽度为 1150px x 50% = 575px

事例源码:https://cdpn.io/shadeed/debug/cca927df45964fbe1a8342ad3ace6d71

Clamp() 函数

clamp()函数作用是返回一个区间范围的值。语法如下:

clamp(MIN, VAL, MAX)

其中MIN表示最小值,VAL表示首选值,MAX表示最大值。意思是,如果VALMINMAX范围之间,则使用VAL作为函数返回值;如果VAL大于MAX,则使用MAX作为返回值;如果VAL小于MIN,则使用MIN作为返回值。

clamp(MIN, VAL, MAX)实际上等同于max(MIN, min(VAL, MAX))

考虑下面的例子

.element {
    width: clamp(200px, 50%, 1000px);
}

假设我们有一个元素,其最小宽度为200px,首选值为50%,最大值为1000px,如下所示:

上面的计算过程是这样的:

  • 宽度永远不会低于200px
  • 内容中间首选值是50%,只有在视口宽度大于400px小于2000px时才有效
  • 宽度不会超过 1000px

事例源码:https://codepen.io/shadeed/pen/924419f15bfdcf0cd0103b0587524b0b?editors=0010

上下文很重要

计算值取决于上下文。 可能是%emremvw/vh。 甚至百分比值也可以基于视口宽度(如果元素直接位于<body>中),也可以基于其父元素。

数学表达式

值得一提的是, clamp() 函数也可以用于数学表达式,而不必借助于 calc(),如下代码所示:

.type {
  /* 强制字体大小保持在 12px 到 100px 之间 */
  font-size: clamp(12px, 10 * (1vw + 1vh) / 2, 100px);
}

用例

侧边栏和主界面

通常,页面的侧边栏是固定的,主界面度是灵活的。 如果视口足够大,我们可以根据视口的大小动态增加侧边栏宽度,这里我们可以使用max()函数为其设置最小宽度。

考虑下面的示例:

.wrapper {
    display: flex;
}

aside {
  flex-basis: max(30vw, 150px);
}

main {
  flex-grow: 1;
}

如果视口大于 500px,则侧边栏的最小宽度为150px(500 * 30% = 150)。

事例源码: https://codepen.io/shadeed/pen/7f9558f31fdf60bc08c827817c10bf3a?editors=1100

标题字体大小

clamp()的一个很好的用例是用于标题。假设我们希望标题的最小大小为16px,最大大小为50pxclamp()函数将为我们提供一个介于两者之间的值。

.title {
    font-size: clamp(16px, 5vw, 50px);
}

在这里使用clamp()是非常适合的,因为它确保了所使用的字体大小是可访问的和易于阅读的。如果换做min(),那么就不能在小的视图中控制字体了。

.title {
    font-size: min(3vw, 24px); /* Not recommended, bad for accessibility */
}

在移动端,字体大小很小。因此,不要对字体大小使用min()函数。当然,我们也可以通过媒体查询来适配,但是这样就错过了一次使用** CSS 比较函数**实战。

如前所述,可以在max()函数中嵌套min()来实现clamp() 效果,该函数将模仿clamp()函数,如下所示:

.title {
    font-size: max(16px, min(10vw, 50px));
}

事例源码:https://codepen.io/shadeed/pen/db76480260c104df00c65991df90a203?editors=1100

装饰性标题

注意看上图标题下面有一个大的半透明的标题,这是一个装饰性的文本,根据视窗的大小来缩放。我们可以使用max()函数和CSS viewport单元来设置它的最小值。

.section-title:before {
  content: attr(data-test);
  font-size: max(13vw, 50px);
}

源码: https://codepen.io/shadeed/pen/e0128b73de7c84cb9b98cf733a3835c4?editors=1100

平滑渐变

当在CSS中使用渐变时,你可能需要对它进行一些调整,使颜色之间的过渡更加平滑。我们先看看下面的渐变:

.element {
    background: linear-gradient(135deg, #2c3e50, #2c3e50 60%, #3498db);
}

注意移动的过渡是有一条比较明显的线分开,这是不好的。我们可以通过使用媒体查询来解决这个问题:

@media (max-width: 700px) {
    .element {
        background: linear-gradient(135deg, #2c3e50, #2c3e50 25%, #3498db)
    }
}

有一种更加简洁的方法就是使用 min() 函数,如下 所示:

.element {
    background: linear-gradient(135deg, #2c3e50, #2c3e50 min(20vw, 60%), #3498db);
}

事例源码:https://codepen.io/shadeed/pen/2c4bf2ded32f66390fdef13409be4a10?editors=1100

透明渐变

当需要在图片上放置文本时,我们应该在图片上加层渐变让文本更加可读。与上一个示例类似,渐变大小应该在小视图和大视图之间有所不同。见下图:

.element {
    background: linear-gradient(to top, #000 0, transparent max(20%, 20vw));
}

事例源码:https://codepen.io/shadeed/pen/babf1bfd4c85eeb1b6f9f549dd0fe602?editors=1100

容器宽度

如果有一个容器,它的宽度应该是它父容器的80%,但不能超过780px,你会用什么?通常,你应该会用max-width,如下所示:

.container {
    max-width: 780px;
    width: 80%;
}

这里使用 min() 函数也可以为元素设置最大值:

.container {
    max-width: min(80%, 780px);
}

事例源码:https://codepen.io/shadeed/pen/3d8b44709b04efdd7336fe91363e3d76?editors=1100

边界与阴影

在一些设计案例中,如果元素边框的宽度和弧度比较大时,在移动时应尽量减小。通过使用clamp(),我们可以根据视窗宽度使其动态。

.element {
    box-shadow: 0 3px 10px 0 red;
    border: min(1vw, 10px) solid #468eef;
    border-radius: clamp(7px, 2vw, 20px);
    box-shadow: 0 3px clamp(5px, 4vw, 50px) 0 rgba(0, 0, 0, 0.2);
}

事例源码:https://codepen.io/shadeed/pen/7b5c7979e09573ca32150ebfc7f74a66?editors=1100

Grid Gap

在一个使用风格布局的界面上,如果我们想根据视口大小来调整网格之间的间距,使用 clamp() 是很容易做到的:

.wrapper {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: clamp(1rem, 2vw, 24px);
}

事例源码:https://codepen.io/shadeed/pen/a14c7d9fcbbae84340a4f83833294f5b?editors=1100

如果在不兼容浏览器使用这些方法

与任何新的 CSS 函数一样,提供后退方案是很重要的。 要实现这一点,我们可以使用以下方法之一:

1.手动添加回退方案

我们可以在使用比较函数之前加一个默认的方式,如下所示:

.hero {
    padding: 4rem 1rem;
    padding: clamp(2rem, 10vmax, 10rem) 1rem;
}

支持的浏览器将忽略第一个,不支持的将使用第一个padding

使用 CSS @supports

我们可以使用@supports检测浏览器是否支持 CSS 比较函数,如下所示:

.hero {
    /* 默认值,用于不支持的浏览器 */
    padding: 4rem 1rem;
}

@supports (width: min(10px, 5vw)) {
   /* 用于支持的浏览器  */
  .hero {
    padding: clamp(2rem, 10vmax, 10rem) 1rem;
  }
}

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://heydesigner.com/everything-i-learned-about-min-max-clamp-in-css/

文章每周持续更新,可以微信搜索**【大迁世界 】第一时间阅读,回复【福利】**有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant