CSS 新的长度单位 fr 你知道么?

859 阅读4分钟
原文链接: zhuanlan.zhihu.com

本文译自:An Introduction to the fr CSS unit。介绍了 CSS Grid 规范中引入的一个新的长度单位 fr,我们一起来看看到底是怎么回事吧,译文走起!

关于 CSS Grid 的激烈讨论到处都是,但我发现很少有讨论 fr 这个新的 CSS 长度单位(规范在这里)的文章。

为了讲清楚,先从一个典型的案例开始,我们看下面的例子,用 CSS 创建一个网格,这个网格一行四列,每列等宽。

<div class="grid">
  <div class="column"></div>
  <div class="column"></div>
  <div class="column"></div>
  <div class="column"></div>
</div>
.grid {
  display: grid;
  grid-template-columns: repeat(4, 25%);
  grid-column-gap: 10px;
}
codepen.io/robinrendle…&amp;amp;amp;amp;amp;amp;lt;img src="https://pic3.zhimg.com/v2-25fbeed5d62b7522f8e188d61f994fa6_b.png" data-rawwidth="731" data-rawheight="347" class="origin_image zh-lightbox-thumb" width="731" data-original="https://pic3.zhimg.com/v2-25fbeed5d62b7522f8e188d61f994fa6_r.png"&amp;amp;amp;amp;amp;amp;gt; codepen.io

在 grid-template-columns 里我们使用了 repeat(),如果你已经知道了 repeat() 的功能可以跳过本段。它是 CSS Grid 引入的最有爱的特性之一!它是一种缩写方式,本质就是为了减少我们重复书写多个值的问题。本来我们可以直接写 grid-template-columns: 25% 25% 25% 25%;,但用 repeat() 看上去更清晰明了,尤其是有很多冗长的宽度表示时(比如 minmax() 表达式)。

repeat 的语法如下:

repeat(number of columns/rows, the column width we want);

可能你还没发现,目前我们的 CSS 代码是有点问题的。

首先,为了使用这个可爱的函数,我们必须做数学题。必须计算一下分成4栏每栏的宽度是百分之多少,不错,这里是 25%。这道题目还算简单,但是如果复杂点我们就需要让浏览器帮我们做。还好我们有 calc() 函数,于是我们的答案可以是 repeat(4, calc(100%/4)),看起来有点复杂呵……不过还有另外一个致命问题:

这个问题就是元素溢出了。4 个 25% 宽的栏加上 10px 的 grid-column-gap 超过了 100%。百分比的工作模式没有问题,但显然结果不是我们想要的。我们希望代码表达的是:每栏的宽度是总宽度的(viewport 的宽度)25%,栏与栏之间的有 10px 的间距。差别很微妙,布局就很尴尬了。

外刊君:repeat(4, calc((100% - 10px * 3)/ 4)) 这样可以工作!

一不小心我们搞出了滚动条:

codepen.io/robinrendle…&amp;amp;amp;amp;amp;amp;lt;img src="https://pic1.zhimg.com/v2-d27deae156242b6cce3d15c360913268_b.png" data-rawwidth="728" data-rawheight="344" class="origin_image zh-lightbox-thumb" width="728" data-original="https://pic1.zhimg.com/v2-d27deae156242b6cce3d15c360913268_r.png"&amp;amp;amp;amp;amp;amp;gt; codepen.io

这个时候 fr 就持证上岗服务我们了。

在定义网格时,fr 的用法与其他 CSS 长度单位 %、px、em 等是一样的。用这个神奇的新单位重写一下代码:

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 10px;
}
codepen.io/robinrendle…&amp;amp;amp;amp;amp;amp;lt;img src="https://pic1.zhimg.com/v2-1228c976fecc866dc41853534fc51f2c_b.png" data-rawwidth="728" data-rawheight="305" class="origin_image zh-lightbox-thumb" width="728" data-original="https://pic1.zhimg.com/v2-1228c976fecc866dc41853534fc51f2c_r.png"&amp;amp;amp;amp;amp;amp;gt; codepen.io

demo 看起来没啥变化,四栏等宽(就是 1/4 或者是 25%)。但是,注意!横向的 overflow 消失了。每个栏的宽度设置为 1fr 后,三个 10px 的间隙首先从总宽度减去,再计算每个栏的宽度!

你可能会bibi说为啥我非要用这个新的 CSS 单位,我继续坚持使用百分比或者 px 有什么不好?好吧,我们再看一个更复杂的例子,显然 fr 是更好的方案。在下面这个例子中,最左边一个有一个导航栏,然后右紧跟着12个 column:&amp;amp;amp;amp;amp;amp;lt;img src="https://pic4.zhimg.com/v2-071d2828ef5ad0fe5c75a9d24cc815d3_b.png" data-rawwidth="1001" data-rawheight="341" class="origin_image zh-lightbox-thumb" width="1001" data-original="https://pic4.zhimg.com/v2-071d2828ef5ad0fe5c75a9d24cc815d3_r.png"&amp;amp;amp;amp;amp;amp;gt;

这种“切图”需求很常见啊,如果不使用 fr,我们只能选择使用额外的 grid 或者 calc 来实现。必须像下面这样思考:

栏的宽度 = (viewport 的宽度 - nav 的宽度) /  栏的数量  * 100%

是,这没问题,但是很丑很痛有没有?一旦我们更改 nav 的宽度,需要再做一遍数学题。所以啊, fr 这个单位完美处理这个问题,代码可读性很强有没有?

.grid {
  display: grid;
  grid-template-columns: 250px repeat(12, 1fr);
  grid-column-gap: 10px;
}
codepen.io/robinrendle…&amp;amp;amp;amp;amp;amp;lt;img src="https://pic1.zhimg.com/v2-f68aca81515b5373e4177b9c02192630_b.png" data-rawwidth="728" data-rawheight="416" class="origin_image zh-lightbox-thumb" width="728" data-original="https://pic1.zhimg.com/v2-f68aca81515b5373e4177b9c02192630_r.png"&amp;amp;amp;amp;amp;amp;gt; codepen.io

我们的方案就是给第1栏设置一个固定宽度,然后重复创建12个栏“平分剩下的自由空间”(从规范的标准解释是这样)。不需要做任何的数学题!易读,最左边的 nav 可以随意更改,剩下的20个栏会自动伸缩。

好了,一点点不动脑的工作让我们的界面更容易维护了。就算将来的某个时候再来看代码也很清晰,说简单点,就算辞职了,后来的“切图仔”也不用跳坑!