Better

Ethan的博客,欢迎访问交流

利用 Grid 网格布局解决 Flex 布局最后一行均匀排列问题

Grid 布局相比 Flex 布局,个人觉得其实更容易理解,只是属性比 Flex 来的更多而已。先总结下属性的基本使用,然后解释下 Flex 存在的问题,以及 Grid 如何解决

基本概念

通过设置 display: grid 启用网格布局。默认情况下,容器元素都是块元素,也可以设置成行内元素,设置为 inline-grid 即可

通过行和列来划分网格,内部的每项默认从左到右依次排列(可以通过 gird-auto-flow 修改默认设置)

通过 grid-template-columns 和 grid-template-rows 来划分网格,你有如下几种方式

  1. 直接设置具体值:比如 100px、30% 等均可,有多少格就设置多少个值
  2. 使用 repeat 函数,减少重复的值,用法:repeat(3, 33.33%),也可以重复多个值,用法 repeat(2, 100px 20px 80px)
  3. 使用 auto-fill 关键字,适用于无法指定多个行列的情况,但是知道具体单元格的大小,容纳尽可能多的单元格,用法 repeat(auto-fill, 100px)
  4. fr 关键字,用于表示比例关系,grid-template-columns: 1fr 2fr; 表示后者是前者的两倍
  5. 使用 minmax 函数指定一个范围,比如 minmax(100px, 1fr)
  6. auto 关键字,表示使用剩余最大宽度,比如 grid-template-columns: 100px auto 100px
  7. 网格线名称,可以通过方括号指定每一根网格线的名字,方便子元素的引用,比如 grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];

划分完网格后,我们可能还需要设置网格之间的间距,这里也有相关属性可直接使用

  • grid-row-gap:用于设置行间距
  • grid-column-gap:用于设置列间距
  • grid-gap: <grid-row-gap> <grid-column-gap>; 如果省略了第二个值,浏览器认为第二个值等于第一个值

为了更方便的引用,还可以直接给每个区域设置名字,通过 grid-template-area 属性,具体用法如下

.container {
    grid-template-area: 'a b c'
                        'd e f'
                        'g h i';
}

如果某些区域不需要命名,则使用点(.)表示

grid 默认是从左往右依次排列,先填满第一行,再开始放入第二行,这种默认行为通过 grid-auto-flow 进行修改

  • row 默认值
  • column 先列后行
  • row dense 和 column dense 表示尽可能紧密填满,尽量不出现空格

排列方式

基本概念中了解主要了解到了如何划分网格和设置间距,如何修改默认排列方式,接下来了解几个用于指定单元格内容的排列方式的属性

justify-items 属性设置单元格内容的水平位置(左中右),align-items 属性设置单元格内容的垂直位置(上中下)。支持的属性有

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

place-items 属性是 align-items 属性和 justify-items 属性的合并简写形式,place-items: <align-items> <justify-items>; 如果省略第二个值,则浏览器认为与第一个值相等。

justify-content 和 align-content 用于指定整个内容区域在整个容器中的排列方式。因为你的内容区域可能并不是完全填满整个容器的,这时候改属性就能排上用处了

  • start - 对齐容器的起始边框。默认值
  • end - 对齐容器的结束边框。
  • center - 容器内部居中。
  • stretch - 项目大小没有指定时,拉伸占据整个网格容器。
  • space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。
  • space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔。
  • space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。

place-content 属性是 align-content 属性和 justify-content 属性的合并简写形式。place-content: <align-content> <justify-content>; 如果省略第二个值,则浏览器认为与第一个值相等。

特殊情况:如果网格只有 3 行,但某个项目指定在第 5 行,这时候会怎么处理呢。浏览器会自动生成多余的网格,以便用于放置项目。grid-auto-columns 属性和 grid-auto-rows 属性用来设置,浏览器自动创建的多余网格的列宽和行高。如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。

项目属性

了解完了划分和排列,接下来具体到子元素的相关属性。

子元素可以通过设置属性,实现跨行和跨列,具体属性如下,网格线从 1 开始

  • grid-column-start 属性:左边框所在的垂直网格线
  • grid-column-end 属性:右边框所在的垂直网格线
  • grid-row-start 属性:上边框所在的水平网格线
  • grid-row-end 属性:下边框所在的水平网格线

除了指定为第几个网格线,还可以指定为网格线的名字。这时候基本概念中的网格线命名就可以用到了。

还有一种简便方法,就是通过 span 关键字实现跨越,也就是说你只需要知道你需要多少格,从哪里开始和结束,通过自动计算完成

相关简写

.item {
  grid-column: <start-line> / <end-line>;
  grid-row: <start-line> / <end-line>;
}

斜杠以及后面的部分可以省略,默认跨越一个网格。

还记得上面通过 grid-template-area 设置的区域名吗,项目也可以直接通过 grid-area 便捷指定放在哪个区域,就不需要设置 start 和 end 了,相对更简单一点

grid-area 属性还可用作 grid-row-start、grid-column-start、grid-row-end、grid-column-end 的合并简写形式,直接指定项目的位置。

.item {
  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
}

子元素自身的特殊排列,我们通过 justify-items 或 align-items 设置内容的排列方式时,如果某个子项目比较特殊,可以通过 justify-self 和 align-self 设置自身的排列方式,取值完成一样

place-self属性是align-self属性和justify-self属性的合并简写形式。place-self: <align-self> <justify-self>; 如果省略第二个值,place-self属性会认为这两个值相等。

解决 Flex 问题

Flex 问题到底是什么呢?

如果我们内容的宽度确定,希望每行极可能的排列更多的元素,如果排不下,则剩余宽度作为间隔均匀分布,使用 flex 布局,代码和效果如下

.container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

效果如下:

8A339A33-2E97-4D9F-9288-F0DFF057F2EB.png

这肯定不是我们所希望的,我们希望最后一行也是正常一次排列。查阅资料,针对 Flex 布局本身的话,多数解决方案是通过添加空的暂位元素来解决,但这会污染 html,显然不是一个优秀的解决方案。这个问题通过 Grid 布局可以轻松解决,代码如下

.container {
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px);
    justify-content: space-between;
}

最终效果如下:

C038E78F-E952-4B6A-ADC9-19DF7AE4E672.png

参考



留言