前端开发者学堂 - fedev.cn

CSS Grid带来的新单位:分数单位fr

发布于 大漠

CSS Grid经过这么多年的发展已经越来越受人青眯了,到目前为止支持率得到近88%的比例。经过这么多年的跟踪和学习,对CSS Grid的特性也是略有所知,但还未达到完全的融汇贯通。因为它有很多的特性,而且这些特性对于CSSer来说很多都是新的概念,比如我们今天要说的分数单位fr就是一个新东东。那么这篇文章,咱们就来一起看看这个特性有什么特性,给我们又能带来什么好处。感兴趣的同学,请继续往下阅读。

简介

在CSS Grid中可以使用任何长度单位来给网格轨道定义大小。比如在grid-template-columnsgrid-template-rows可以使用pxremvw100%等CSS单位来设置大小,除此之外,CSS网格还引入了另一个长度单位来帮助我们创建网格轨道大小。这个新单位就是我们今天要聊的fr单位。大家喜欢把它称为分数单位。那么他究竟有什么作用呢?

在MDN是这样描述的:

新的fr单位代表网格容器中可用空间的一等份。

就从这样的描述或许还是会令人感到困惑。不用担心,我们继续往下阅读,我想可以帮你解惑的。

对比性思考

**fr**是代表网格容器中可用空间的一等份,即1fr。如果是2fr那么就是把容器剩余的空间分成两等份。看到这里,是否会想起Flexbox布局中的flex呢?比如我们有这样的一个示例:

<div class="flex">
    <aside>Sidebar</aside>
    <main>Main</main>
</div>

.flex {
    width: 600px;
    background: orange;
    display: flex;
    min-height: 50vh;
}

aside {
    width: 200px;
    background: #f36;
}
main {
    margin-left: 20px;
    background: #f63;
    flex: 1;
}

效果如下:

可以看出,main元素设置flex:1时也占用了容器剩余的空间(600px - 200px - 20px = 380px )。从浏览器的查看器中可以验证,计算是无误的:

在上面的示例中,我们再来变更一下,再添加一个侧边栏:

main {
    flex: 2
}
aside:last-of-type {
    flex: 1
}

使用浏览器再次验证我们的计算是不是正确的:

上图可以告诉我们答案,和我们最初想的是一样的。Flexbox中的flex也可以把Flexbox容器剩余的容器进行平分。具体平分多少等份需要根据Flexbox容器子元素,也就是Flex项目使用了几等份。比如上例中的main使用了flex:2,第二个aside使用了flex:1。也就是说,此例中把Flexbox容器剩余的空间分成了三等份,其中main占三分之二,剩余的三分之一给了右侧的aside元素。

Flexbox中的flex属性是flex-basisflex-shrinkflex-grow三个属性的简写属性,而其盒模型的计算是相当复杂的,感兴趣的可以阅读《深入理解 Flexbox 布局以及计算》一文。

正因为如此,所以flex属性常用来把一个容器分成均匀的等份,特别是在移动端的时候,制作Tabbar效果,特为显著:

如果我们用CSS Grid来实现上图的效果。其实就是一个一行五列的网格,并且每列都等宽:

<footer>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</footer>

footer {
    width: 750px;
    display: grid;
    grid-template-columns: 20% 20% 20% 20% 20%;
}

fr单位还没出来之前,大家可能会想到的是百分比单位,正如上面的代码所示。也正因为,列表项刚好能被整除,所以效果接近完美:

大家看到示例了,我们有写了五个20%,其实在CSS Grid布局中有一个函数repeat()可以让我少写重复的代码:

grid-template-columns: repeat(5, 20%)

我们还是回到主题上来。上面的示例中列表项可以被整除,那么问题来了,如果容器不能被列表项整除,比如列表项是3这样的。那么结果就会差强人意了。或者又说,如果列表项之间有间距(比如说10px),使用百分比相对而言就要麻烦了。因为此时按计算,每个列表项的宽度就变成了(100% - 10px * 4) / 5。如果知道容器的值,我们换成固定值也好计算,比如(750px - 4 * 10) / 5 = 142px

footer {
    display: grid;
    grid-template-columns: repeat(5, 142px);
    grid-gap: 10px;
}

在不知道容器具体宽度值,比如开始所说的百分比,那么就需要借且calc()函数帮我们,calc((100% - 4 * 10px) / 5):

footer {
    display: grid;
    grid-template-columns: repeat(5, calc((100% - 4 * 10px) / 5));
    grid-gap: 10px;
}

得到的效果和上图将是一样的。

fr登场

正如前面所示,calc(100% - 4 * 10px)其实就是计算容器扣除网格间距(4 * 10px = 40px)所剩下的容器空间。也就可以想象像成:

1fr = calc(100% - 4 * 10px)

而我们示例有五个列表项,每个列表项都是均等的,所以将会分成五等份,即可五个1fr,用repeat()的话可以表示成repeat(5, 1fr)

footer {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-gap: 10px;
}

得到的效果将是一致的:

此时我们要去掉grid-gap,那么就得到我们想要的均分列表项,也最终得到我们想要的效果:

简单的用几张图来向大家展示fr在CSS Grid中是如何计算的。

现在我们再来看一个不是均分的:

#app {
    display: grid;
    grid-template-columns: 3fr repeat(4, 1fr) 2fr;
    grid-gap: 20px;
    max-width: 1200px;
}

上面我们看到的都是使用fr为单位的网格项。其实还可以和auto%px等混合在一起使用。比如:

#app {
    display: grid;
    grid-template-columns: auto repeat(5, 1fr);
    grid-gap: 20px;
    width: 1200px;
}

再来看一个%的:

#app {
    display: grid;
    grid-template-columns: 30% repeat(4, 1fr) 20%;
    grid-gap: 20px;
    width: 1200px;
}

除些之外,还可以多种混合使用:

总结

文章中介绍了fr单位如何使用以及它是如何计算的。从上面的示例中可以看出,fr单位非常的强大。虽然很强大,但该单位可以说是CSS Grid中的专有的,在别的地方使用是无效的,好比flex:1只能在Flexbox布局中使用。另外fr使用的时候,可以结合CSS其他单位一起使用。

如果你对fr单位有更深入的了解,欢迎在下面的评论中与我们一起分享。