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 都会用到的. 尽量看它们不同的地方, 发挥它们的长处即可.

相关