<译> 深入minmax()

翻译系列第六篇,深入minmax(),原文地址

已经有很多介绍CSS grid教程了,我自己也写过很多。然而,我注意到因为多数文章都是泛泛而谈没有足够的解释和深入的用力,导致对于minmax()函数似乎存在误解。minmax()非常的强大而有用,因此我认为写一个完整的minmax()指南有助于减小差距。

在这篇文章中,我们会深入了解minmax(),学习如何使用、何时使用、以及为什么使用它。我希望在读完之后你会对于它有一个完整的理解。黑喂狗

基础介绍

按照CSS规范,minmax(min, max)的定义如下:

Defines a size range greater than or equal to min and less than or equal to max.

我们可以使用minmax()作为grid行或者列的值,看一个最基础的例子:

1
2
3
4
5
.o-grid {
display: grid;
grid-template-columns: minmax(200px, 500px) 1fr 1fr;
grid-gap: 1rem;
}

分析一下:

  • 我们有三个grid列(纵行)
  • 第一列的宽度是minmax(200px, 500px),最小值是200px,最大值是500px
  • 另外两列是每列1fr,这也意味着他们会占用剩余的可用空间

例子继续延伸,我们还应该考虑到视口的大小,当视口非常小的时候会怎样呢?简单说就是水平滚动条,我觉着没人喜欢在页面上看到滚动条,除非是故意的

这也意味着minmax()本身并不能用来处理响应式,我们需要自己处理这个问题——在稍后的例子中会讨论到

Minmax()验证

如果minmax(min, max)中的最小值大于最大值,那么最大值将被忽略,minmax(min, max)会被视作最小值

另外一定要记住,使用1fr作为最小值是无效的,它只适用于最大值。这比最小值大于最大值更糟糕,整个声明都会被忽略

使用0作为最小值

minmax(0, 500px)这样会发生什么——宽度最小为0,最多不超过500px,这也意味着,如果视口宽度不够,列宽大小将进行调整

一个简单的Grid

创建一个三列的网格,列宽最小为200px

1
2
3
4
5
.o-grid {
display: grid;
grid-template-columns: minmax(200px, 1fr) minmax(200px, 1fr) minmax(200px, 1fr);
grid-gap: 1rem;
}

注意,我们使用repeat()函数来避免minmax()重复三次

1
2
3
4
5
.o-grid {
display: grid;
grid-template-columns: repeat(3, minmax(200px, 1fr));
grid-gap: 1rem;
}

以上的方法虽然有效,但是不推荐使用

手动更改列数

如果需要不同的列数,我们需要手动进行修改,但是我认为这不合理,CSS Grid应该做到更多

而且因为我们显式地定义了列的数量,所以当视口宽度很小时,浏览器不能让它们换行,这将导致一个水平滚动条

怎么去掉这个滚动条呢?我们要让浏览器知道,如果视口的宽度不够,那么列的数量应该减少

如果是flex盒子,我们需要添加flex-wrap: wrap到父容器中

1
2
3
4
.parent {
display: flex;
flex-wrap: wrap;
}

在CSS Grid中,我们需要使用auto-fill或者auto-fit关键字

使用auto-fill或者auto-fit关键字

auto-fillauto-fit之间的区别非常微妙,简而言之,auto-fit会扩展每一项以填充可用空间,而auto-fill则会保留可用空间不会扩展网格项

使用auto-fill/fit可能会得到相同结果,这取决于视口大小,看看这个视频(原视频地址

…(删掉了一小部分和上面动画差不多的演示)

好了我已经解释了mixmax()的原理,让我们看一些示例

示例

我认为这是minmax()最常见的用例,它创建了一个响应式的卡片容器

1
2
3
4
5
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 1rem;
}

当我刚学CSS Grid的时候,理解这个grid-template-columns是非常困难的。注意这个小于250px是很重要的,因为视口小于250px时会出现滚动条

为了解决这个问题有两个方法,一个是媒体查询,将grid-template-columns设为1fr,当视口足够大才会应用minmax()

1
2
3
4
5
6
7
8
9
10
11
.wrapper {
display: grid;
grid-template-columns: 1fr;
grid-gap: 1rem;
}

@media (min-width: 300px) {
.wrapper {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
}

另一个方法就是使用CSS的比较函数,但是这个方法很现代,要注意浏览器兼容性

1
2
3
4
5
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
grid-gap: 1rem;
}

使用min()比较函数作为minmax()的第一个值,会发生什么?

  • 如果viewport宽度小于250px,那么minmax()函数的第一个值将是父宽度的100%
  • 如果viewport大于250px,那么minmax()的第一个值将是250px

我们用更少的CSS实现了更好的解决方案。如果你想了解更多关于CSS比较函数的知识,我写了一篇关于它们的详细文章

用ch单位作为包装容器

minmax()的一个有趣用例是使用它创建文章布局。对于本例,内容是水平居中的

1
2
3
4
5
.wrapper {
display: grid;
grid-template-columns: minmax(1rem, 1fr) minmax(auto, 70ch) minmax(1rem, 1fr);
grid-gap: 1rem;
}

左右两列作为旁边的留白,中间才是我们的焦点。注意这个值minmax(auto, 70ch),这意味着,该列的最大宽度为每行70个字符。为了提高可读性,这是一个理想的字符长度

这对于移动端来说非常有用,因为第一个和最后一个列将以最小宽度1rem折叠

不负责任使用auto-fit的缺陷

使用自动适应很诱人。而其缺点是,当内容是动态的而且无法控制时可能会崩溃

1
2
3
4
5
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 1rem;
}

当我们有四列时,一个看起来完美的卡片网格。然而,当只有一张卡片时,它将扩展以填满剩余的可用空间

…(又省略一点对于上面自动填充的扩展

赞助

原作者的电子书:Debugging CSS

赞助地址: buy me a coffee