Grid

a two-dimensional grid-based layout system

CSS grid layout,又称 CSS grid 或 grid,是一种基于二维网格的布局系统,它擅长将页面划分成行和列。

和 table 一样,grid 也能让元素对齐到 row 和 column 中。但 grid 能更容易地实现更多其它布局,比如它的子元素可以 position(定位)自己,即子容器实际上是 overlap(重叠)和 layer(分层)的,类似于 CSS 的 positioned elements(定位元素)。

和 flexbox 类似,grid items 的 order 也能通过 CSS 来设置,好处是可以用 media query 来灵活摆放。

1. 相关术语

  1. grid container:设置了 display: grid 的元素

  2. grid item:是 grid container 的(直接)子元素

  3. grid line:是构成 gird 结构的 dividing lines,位于行或列的任意一侧

    • 可以是 vertical 的 column grid lines

    • 也可以是 horizontal 的 row grid lines

  4. grid track:两条相邻 grid lines 之间的空间。可以视为 grid 的 row 或 column

  5. grid area:被四条 grid lines 围起来的总空间。可能是由多个 grid cells 组成的

  6. grid cell:被两条相邻 row grid lines 和两条相邻 column grid lines 围起来的空间。它是 grid 的 unit

2. container 属性

2.1 display

定义了一个 grid container,为其内容建立了一个新的 grid formatting context(grid 格式化上下文)。

display: grid;         /* block-level grid */
display: inline-grid;  /* inline-level grid */

2.2 行和列

2.2.1 “布局”行和列

  • grid-template-columns

  • grid-template-rows

以上两个属性用“以空格分隔的 values 列表”的形式定义了 grid 的 columns 和 rows,其中 value 是 track size 的值,它们之间的空间就是 grid line。

value 的取值可以是:<track-size>, <line-name>

(1)<track-size>

/* 列 */
grid-template-columns: 1fr 1fr 1fr;    /* fr: a fraction of the free space */
grid-template-columns: repeat(3, 1fr); /* 效果同上 */
grid-template-columns: 50px 1fr 100px; /* <length> */
grid-template-columns: 10% 1fr 30%;

/* 行 */
grid-template-rows: 1fr 1fr;

(2)<line-name>

grid lines 会被自动分配对应的数字,正序是从 1 到 n,倒序是从 -1 到 -n。如下:

也可以给 grid lines 命名。比如:

/* grid lines 用默认编号 */
grid-template-columns: 40px 50px auto 50px 40px;

/* 给 grid lines 命名 `[]` */
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];

/* 给一个 grid line 命多个名字 `[?-?]` */
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];

如果设置的 <line-name> 是重复的,可以用 repeat() 简化下。比如:

grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
grid-template-columns: repeat(3, 20px [col-start]);

上面代码的多个 grid lines 有相同的名字,如果想引用某个 line,可以用 line name 和 count。比如:

grid-column-start: col-start 2;

2.2.2 给行和列“贴瓷砖”

grid-template-areas 定义了一个 grid template,通过引用“子容器”的 grid-area 属性指定的 grid area 的 name。

grid-template-areas 本身就提供了 grid structure 的可视化。看个例子:

/* 父容器 */
.grid {
    display: grid;
    /* 会创建一个 4 列 3 行的 grid */
    grid-template-areas:
        "header header header header" /* 重复的 grid-area name 会让内容横跨这些 cells */
        "main main . sidebar"         /* . 表示 empty cell */
        "footer footer footer footer";
}

/* 子容器 */
.grid>div:nth-child(1) {
    grid-area: header;
    background-color: orange;
}

.grid>div:nth-child(2) {
    grid-area: main;
    background-color: deepskyblue;
}

.grid>div:nth-child(3) {
    grid-area: sidebar;
    background-color: pink;
}

.grid>div:nth-child(4) {
    grid-area: footer;
    background-color: green;
}

关于 grid-template-areas 属性的相关说明:

  1. 每个 row 必须有相同数量的 cells,否则该声明会失效

  2. 连续的多个 . 只代表一个 empty cell,除非它们之间有“空格”分隔符

  3. 它不 name(命名)grid lines,只 name(命名)areas,虽然此时 area 两端的 lines 会被自动命名。比如 grid area 是 foo,那么该 area 起始的 row line 和 column line 都叫 foo-start,最后的 lines 都叫 foo-end。这就意味着,有的 line 可能会有多个名字,比如上例中最左侧的 line 有三个名字 header-start, main-start, footer-start

  4. 当它设置的 column 的数量和 grid-template-columns 的个数不一致时

    • 优先取 grid-template-columns 的值

    • grid-template-areas 少了,就用其它子容器补齐

    • grid-template-areas 多了,则多出来的子容器 width:auto(整体会保证列对齐)

  5. 可以这样理解:

    • grid-template-columns/rows 负责 layout(布局)

    • grid-template-areas 负责 span(平铺/贯穿/横跨)

当 grid-template-columns 值更大时,取它
当 grid-template-columns 值更小时,若子没 width 则相当于不存在
当 grid-template-columns 值更小时,grid-template-area 多出来的列 width 是 auto

2.2.3 属性缩写

grid-template 是以上三个属性的缩写,格式是:

<grid-template-areas> <grid-template-rows> / <grid-template-columns>

看几个例子,代码如下:

grid-template: 
            "a a a" 40px
            "b c c" 40px
            "b c c" 40px / 1fr 1fr 1fr;

grid-template: 
            "b b a" auto
            "b b c" 2ch
            "b b c" 1em / 20% 20px 1fr;

grid-template: 
            "a a ." minmax(50px, auto)
            "a a ." 80px
            "b b c" auto / 2em 3em auto;

以上代码,会依次显示下面的布局:

相关说明:

  1. 格式 <grid-template-rows> / <grid-template-columns> 会把 grid-template-areas 设置成 none

  2. 当设置 grid-template: none 时,表示这三个属性的值都是它们的 initial values。也就是说,grid-template 不会隐式重置 grid properties,而通常写 none 都是想 reset 各个属性的值。所以,与缩写相比,更推荐用单个属性

  3. 此外,个人的使用感受是:不推荐用缩写。一是功能上杂糅了对 rows 和 columns 的“布局”和“贴片”,二是视觉上也怪眼花缭乱的...

2.3 分配“整体”的剩余空间

有时,内容的总 size 会比 grid container 的小,此时就可以用以下属性设置 grid 在 row 或 column 上的对齐。

  1. justify-content:在 row axis 上分配剩余空间

  2. align-content:在 column axis 上分配剩余空间

  3. place-content 缩写:<align-content> / <justify-content>

取值可以是:

  • start, end, center

  • stretch

  • space-around, space-between, space-evenly

2.4 cell 内沿 axis 的对齐

用来设置 grid items 在 grid cell 里沿 row axis 或 column axis 的对齐。

  1. justify-items

  2. align-items

  3. place-items 缩写:<align-items> / <justify-items>

取值可以是:

  • 公共取值:start, end, center, stretch

  • baselinealign-items 属性时

2.5 间隔

指定 grid line 的 size,可以视作是 columns 之间或 rows 之间的 gutter(间距)with,不含外边缘。

  1. row-gap

  2. column-gap

  3. gap 缩写:<row-gap> <column-gap>

/* standard */
row-gap: 15px;
column-gap: 10px;
gap: 15px 10px;

/* 旧用法 */
grid-row-gap: 15px;
grid-column-gap: 10px;
grid-gap: 15px 10px;

2.6 指定隐式创建的 track size

grid-auto-colums 指定隐式创建的 track size。

隐式创建,也称自动生成。当 grid items 多于 grid cells 时,或当一个 grid item 放在了显式 grid 之外时,就会创建隐式 track。这样做的好处是,让 grid 更灵活地摆放它的 items,因为我们可以不必(显式地)指定每个 track,也不必手动放置每个 item。显式指定 track 的属性有 grid-template-rowsgrid-template-columns

通过两个例子,感受下增加了 grid-auto-colums 属性之后的 UI。如下:

说明:

  • grid-column: 5 / 6 表示从 column line 5 到 column line 6

  • grid-row: 2 / 3 表示从 row line 2 到 row line 3

2.7 有隐式 track 时如何放置 items

当有创建隐式 track 时,就会启动 auto-placement algorithm(自动放置算法)来布局 items。grid-auto-flow 属性就是用来控制该算法的工作方式的,它可以指定 items 如何流入 grid。

取值可以是:

  • row(默认):依次填充每 row,并根据需要添加新 row

  • column:依次填充每 column,并根据需要添加新 column

  • dense:如果后面有更小的 items 来了,则尝试更早地填充 grid holes

  1. 单词“dense”:密集的,稠密的

    • dense 算法,会回溯找能填的 holes,所以 items 可能会乱序

  2. 单词“sparse”:稀少的,稀疏的

    • sparse 算法,只向前移动 items,但从来不回溯,所以 items 是有序的

看个例子:

.container {
    display: grid;
    grid-template-columns: repeat(5, 60px);
    grid-template-rows: repeat(2, 30px);
}
.item:nth-child(1) {
    grid-column: 1;
    grid-row: 1 / 3;
}
.item:nth-child(5) {
    grid-column: 5;
    grid-row: 1 / 3;
}

当分别设置 grid-auto-flow 的值是 rowcolumn 时,items 的布局依次如下图:

.container {
    grid-auto-flow: row;
}

.container {
    grid-auto-flow: column;
}

2.8 grid 缩写

grid 是个缩写属性,用来设置所有 explicit(显式)和 implicit(隐式)的 grid 属性。

  1. grid-template-rows

  2. grid-template-columns

  3. grid-template-areas

  4. grid-auto-rows

  5. grid-auto-columns

  6. grid-auto-flow

缩写的属性值的形式看起来挺费劲的,这里就不展开介绍了,等把单个属性用熟练了再补充。

3. items 属性

3.1 放置和堆叠

通过引用特定的 grid lines 来确定 grid item 的位置。

当 items 之间相互重叠时,可以使用 z-index 控制它们的堆叠顺序。如果没有指定 grid-xxx-end,则 item 默认会跨 1 个 track。

  1. grid-column-start

  2. grid-column-end

  3. grid-row-start

  4. grid-row-end

  5. grid-column 缩写:<grid-column-start> / <grid-column-end>

  6. grid-row 缩写:<grid-row-start> / <grid-row-end>

eg1. 使用默认编号的 grid line

grid-column-start: 2;
grid-column-end: 4;      /* 从 line2 到 line4(实际跨了2列) */
grid-column-end: span 3; /* 从 line2 开始,跨 3 列 */

eg2. 命名的 grid line

/* 图左 */
.item-a {
    grid-column-start: 2;
    grid-column-end: five;
    grid-row-start: row1-start;
    grid-row-end: 3;
}
/* 图右 */
.item-b {
    grid-column-start: 1;
    grid-column-end: span col4-start;
    grid-row-start: 2;
    grid-row-end: span 2;
}

eg3. 缩写

.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}

3.2 给 item 命名

grid-area 属性可以给 item 一个名字,以便被 grid-template-areas 属性引用。

grid-area: header;
grid-area: main;
grid-area: sidebar;
grid-area: footer;

grid-area 属性也可以用作更短的缩写。

/* <grid-row-start> / <grid-column-start> / <grid-row-end> / <grid-column-end> */
grid-area: 1 / col4-start / last-line / 6;

3.3 cell 内沿 axis 的对齐

设置本 item 在单个 grid cell 里沿 row axis 或 column axis 的对齐方式

  1. justify-self

  2. align-self

  3. place-self 缩写:<align-self> / <justify-self>

作用同父容器的在 cell 内沿 axis 对齐,只是这三个属性只控制本 item。

主要参考

Last updated