Grid 布局相比 Flex 布局,个人觉得其实更容易理解,只是属性比 Flex 来的更多而已。先总结下属性的基本使用,然后解释下 Flex 存在的问题,以及 Grid 如何解决
基本概念
通过设置 display: grid 启用网格布局。默认情况下,容器元素都是块元素,也可以设置成行内元素,设置为 inline-grid 即可
通过行和列来划分网格,内部的每项默认从左到右依次排列(可以通过 gird-auto-flow 修改默认设置)
通过 grid-template-columns 和 grid-template-rows 来划分网格,你有如下几种方式
- 直接设置具体值:比如 100px、30% 等均可,有多少格就设置多少个值
- 使用 repeat 函数,减少重复的值,用法:repeat(3, 33.33%),也可以重复多个值,用法 repeat(2, 100px 20px 80px)
- 使用 auto-fill 关键字,适用于无法指定多个行列的情况,但是知道具体单元格的大小,容纳尽可能多的单元格,用法 repeat(auto-fill, 100px)
- fr 关键字,用于表示比例关系,grid-template-columns: 1fr 2fr; 表示后者是前者的两倍
- 使用 minmax 函数指定一个范围,比如 minmax(100px, 1fr)
- auto 关键字,表示使用剩余最大宽度,比如 grid-template-columns: 100px auto 100px
- 网格线名称,可以通过方括号指定每一根网格线的名字,方便子元素的引用,比如 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;
}
效果如下:
这肯定不是我们所希望的,我们希望最后一行也是正常一次排列。查阅资料,针对 Flex 布局本身的话,多数解决方案是通过添加空的暂位元素来解决,但这会污染 html,显然不是一个优秀的解决方案。这个问题通过 Grid 布局可以轻松解决,代码如下
.container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
justify-content: space-between;
}
最终效果如下: