CSS – Grid
前言
有一种布局方式叫 Layout Grid 网格布局.
在 有介绍过.
在 也有讲到过
要实现这种布局, 可以用 也可以用 Grid. Bootstrap 用的方法就是 Flex.
Grid 出生在 Flex 之后, 所以先掌握 Flex 在学 Grid 会比较轻松, 但它们 2 个是不一样的东西哦. 虽然有共同点但是整体还是区别蛮多的.
参考:
阮一峰 CSS Grid 网格布局教程
CSS Grid Layout Crash Course
理解
Flex 的用法是, 有一些 item 我们想把它排成 1 行或者 1 列.
Grid 的想法是我先做一个布局 (类似 table) 然后 item 在一个一个依据规则放进来.
所以它们的思路是不一样的. Flex 简单的很多. 它只考虑 1 行或者 1 列.
Grid 考虑的是整体, 所谓的 2 direction.
HTML 结构
<div class="container"> <div class="item">item1div> <div class="item">item2div> <div class="item">item3div> <div class="item">item4div> <div class="item">item5div> <div class="item">item6div> <div class="item">item7div> <div class="item">item8div> <div class="item">item9div> div>
和 Flex 完全一样. 也只有 first layer 才是 grid item.
Grid 结构: Row, Column, Cell, Line
黄色 item 1, 2, 3 叫 row 行
红色 item 1, 4, 7 叫 column 列
蓝色 2 条线叫 column line 1, column line 2
青色 item 9 叫 cell
和 table 的叫法差不多.
grid-template-columns/rows
Grid 的第一步是先定义布局. 多少 column, row, 多大. 不需要去考虑 item 先.
display: grid;
grid-template-columns: 100px 100px 100px;
这表示有 3 个 column, 每一个 100px width, 大概是这个画面
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px;
grid-template-rows 表示 3 个 row, height 100px, 大概是这个画面
于是网格就建立起来了.
item 会一个一个的被丢进去. 默认的顺序是 Z 字形
我们只定义了 2 rows 100px 所以第 3 行的 height 是 hug content (后面会讲到细节)
这就是 Grid 的 flow, 先布局, 然后 item 依据规则插入进去,
repeat(), auto-fill, auto-fix, px, percent, fr, auto, minmax()
repeat()
它就是一个方便而已. 第一次参数是数量, 第 2 参数是值
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(2, 100px 100px);
auto-fill
grid-template-columns: repeat(auto-fill, 100px);
auto-fill 作为 repeat 的第一参数表示自动计算 column 数量, base on container width 和 item width. 尽可能的用完 container width
auto-fix
参考:
grid里 auto-fill和auto-fit的区别
px, percent, fr, auto, minmax()
这些都是用来控制 cell width 的. px, percent 就不多说了.
fr 是比例 fraction
repeart(3, 1fr) 表示 3 个 columns 每一个 33.33%
1fr 1fr 2fr 则表示 25% 25% 50%
auto 它会依据剩余的空间和内容的空间做计算
下面是 repeat(4, auto) 的效果, 它并不是平均的, item 2 的 content width 比其他的大.具体算法没去研究.
因为一般上很少放多个 auto 的. 通常是其它都有值, 其中 1 个 auto.
minmax(100px, 1fr) 表示 auto 但是最小 100px 最大 1fr.
小总结
Grid 有 2 个步骤,
第一步是设定好布局, 多少 column, rows, 每个 cell 多大.
第二步是 item 规则插入.
到这里第一步需要的属性都介绍了. 去下一步 item 规程插入.
grid-column/row
默认情况下 1 item 会被插入到 1 个 cell 里头.
可以通过几种方式改变这个效果.
grid-template-columns: repeat(3, 1fr);
3 个 columns, 1 item 1 cell 长这样.
grid-column
用 grid-column 修改它
&:nth-child(1) { grid-column: 3 span; }
3 span 表示这个 item 要占据 3 column cell. 所以效果是
另一种表达方式是
grid-column: 1 / 4;
它表示 line 1 to line 4, 和 3 span 是等价的 (1 / -1 也是等价的, -1 是从后面算起第 1 条, 也就是 line 4)
混写可以哦, 1 / 2 span 从 line 1 开始 2 个 column cell.
grid-row
和 grid-column 同理, 只是方向不一样
grid-column: 1 / 2 span;
grid-row: 1 / 2 span;
效果
grid-area
可以通过 grid-area 混写 grid-column/row 哦
grid-area: 1 / 1 / 2 span / 2 span
它的顺序是 grid-row-start, grid-column-start, grid-row-end, grid-column-end
grid-template-area
除了 grid-template-column/row 还有一个叫 area 所见即所得布局, 它是这样的.
grid-template-areas:
"a a b c"
"d e f ."
"g h i .";
item 定义 grid-area: area-name
<div class="container"> <div class="item" style="grid-area: a">item1div> <div class="item" style="grid-area: b">item2div> <div class="item" style="grid-area: c">item3div> <div class="item" style="grid-area: d">item4div> <div class="item" style="grid-area: e">item5div> <div class="item" style="grid-area: f">item6div> <div class="item" style="grid-area: g">item7div> <div class="item" style="grid-area: h">item8div> <div class="item" style="grid-area: i">item9div> div>
第 1 排 a a b c, 所以 item 1 占据 2 column cell.
第 2 排结尾 d e f . 的点表示这个 cell 无用, 不放入 item
效果
grid-auto-flow
item 插入是有顺序的, 默认是 Z 字形, 先行后列.
grid-auto-flow 可以改变这个顺序.
grid-auto-flow: row 先行后列, defualt, 这也是为什么只设置 display: grid 是没有效果的 (不像 flex 一设置就有效果了), 因为 item 先插入 row.
grid-auto-flow: color 先列后行
如果说 item 太大塞不进会怎样呢?
item 3 是 span 2, 塞不进第 3 个 cell 于是被放到下面了, cell 3 则空白了.
通过 grid-auto-flow: row dense 可以让它智能排位, 尽可能不留空洞.
item 3,4 span 2 所以无法放进去. 结构 item 5, 6 反而放到了前面. 这就是 dense 的效果了.
grid-auto-columns/rows
假设我们只定义了 9 个 cell, 但是我有 12 个 item 会怎么样呢?
grid 会 auto 创建 rows 来满足多出来的 item, 看例子:
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-auto-rows: 50px;
grid-auto-rows 的写法和 grid-template-rows 是一样的.
上面声明了 9 个 cell 和自动创建 row 的 height 是 100px, 效果:
如果写 50px 100px 表示第 2 个自动 row 是 100px 高. 第 3 个又是 50px 第 4 个又是 100px 以此类推.
如果没有定义 grid-auto-rows 等价于 auto (hug content)
gap (grid-gap)
cell 的间距. 如果 item 2 span 的话, item width = cell1 + gap + cell2
gap: 10px 20px;
gap: row column
justify-items, align-items, justify-content, align-content
container
justify-items: center;
align-items: center;
item
justify-self: center;
align-self: center;
和 Flex 类似, container 只是一个方面批量 set 而已.
justify-items 和 justify-self 只有 Grid 才有, flex 是没有的哦. 看效果体会
justify 控制 row, align 控制 column, 它控制的是 item 在 cell 里面的 alignment.
此外, Grid 也有 justify-content, align-content
justify-content: center;
align-content: center;
它控制的是整个 grid cell 和 container 的 alignment
place-items 是 justify-items 和 align-items 的 shorthand
place-items: center center;
place-items: align-items justify-items;
与 Flex 的对比
Flex (direction row)
justify-content: align horizontal all items with container.
align-content: align vertical all items with container. (only when wrap)
align-items: 批量操作
align-self: align vertical item with container
Grid
justify-content: align horizontal all cells with container. (Flex 有)
align-content: align vertical all cells with container. (Flex 有)
justify-items: 批量操作
align-items: 批量操作 (Flex 有)
place-items: shorthand
justify-self: align horizontal item width cell
align-self: align vertical item width cell (Flex 有)
place-self: shorthand
Grid vs Flex
参考:
CSS Grid vs Flexbox
Flexbox vs. CSS Grid — Which is Better?
Flexbox or grid - How to decide?
虽然有些效果 Grid, Flex 都可以实现, 但我们尽量看它们不同的地方, 这样才能各取所长.
我喜欢这 2 张对比图, 看它的线, Grid 十字对齐
再看看 Flex 的, 它的 vertical 线是对不上的. 所谓的 2 direction vs 1 direction
Grid 重叠
flex 做不到重叠, 重叠在一些情况下很不错用, 可以取代 position absolute.
比如这种
Grid + Flex
Grid 适合大布局, 整体那种, flex 适合小布局. 所以很多排版会用 Grid 里面加 Flex.
可以看这个.Using Flexbox + CSS Grid Together: Easy Gallery Layout
Structured layout vs intrinsic sizing
Flex 擅长做这种, intrinsic sizing, 那种想 shrink 的
Grid 擅长做这种, 2 边都有比较固定的尺寸的.
总结
如果你的思路是, 有一些 item 我要排成 1 行或 1列, 那么首先 Flex.
如果你的思路是, 我有一个结构 like table, 然后有 item 要放进去, 那么首选 Grid.
通常一个项目里, Grid, Flex 都会用到的. 尽量看它们不同的地方, 发挥它们的长处即可.