Grid CSS 布局使用总结

2,887 阅读12分钟

Grid 布局是一种强大的CSS布局方案, 它使用网格的形式存放子元素,以便使用行和列的概念管理和控制容器和子元素。在使用 Grid 布局的时候始终把容器当作是一个多行多列的网格有助于更准确的实现 UI 效果。

基本概念

    <div class="container">
        <div class="item"><span>A</span></div>
        <div class="item"><span>B</span></div>
        <div class="item"><span>C</span></div>
        <div class="item"><span>D</span></div>
        <div class="item"><span>E</span></div>
        <div class="item"><span>F</span></div>
    </div>

容器

容器是网格的实现区域,代码中的 container

项目

在容器内部生命的直接子元素, 代码中的 item。 在直接子元素中存在的元素并不是项目,不会受到 Grid 布局的影响。

行和列

脑补。。。

网格线

划分网格的线, 垂直网格线和水平网格线分别划分了列和行。

单元格

单元格和项目概念容易冲突, 单元格是网格线划分出来的区域,是概念上的存在, 而项目是 html 元素。

容器属性

Grid属性布局分为容器属性和项目属性, 这与 Flex 布局的属性分类是相似的。

定义一个容器

下面的代码中在 html 层面定义了一个容器 .container

    <div class="container">
        <div class="item"><span>A</span></div>
        <div class="item"><span>B</span></div>
        <div class="item"><span>C</span></div>
        <div class="item"><span>D</span></div>
        <div class="item"><span>E</span></div>
        <div class="item"><span>F</span></div>
    </div>

而使用 display:grid 就可以在 css 层面使 .container 变为一个 Grid 容器。

.container {
    dispaly: grid;
}

如图,在定义了 .containerGrid 布局后,查看元素时, .container 已经变为了网格布局。 查看代码

定义列/行

在定义了 Grid 容器后,紧接着看需要定义行和列。

定义列 grid-template-columns

grid-template-columns 用来定义网格包含多少列,以及每一列的宽度。

如下定义容器包含6列, 每一列的宽度为 100px;

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px 100px 100px 100px;
}

定义行 grid-template-rows

grid-template-rows 用来定义网格包含多少行,以及每一行的高度。

如下定义容器包含2行, 每一列的宽度为 100px;

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px 100px 100px 100px;
    grid-template-rows: 100px 100px;
}

查看上述代码

通过定义容器以及行与列, 就已经完成了整个 Grid 布局的整个架构, 下面看一些定义容器属性的技巧

display: inline-grid

使用 display:grid 声明一个容器, 容器以块级元素存在, 如果需要是容器变为行级元素可以使用 display:inline-grid

inline-grid

repeat()

在定义列或者行时, 如果需要定义多个相同的列或者行可以使用 repeat() 函数。

/* 定义一个有100px*100px 方格组成的5行4列的容器 */
.container {
    display: grid;
    grid-template-columns: repeat(4, 100px);
    grid-template-rows: repeat(5, 100px)
}

repeat() 接受两个参数, 第一个参数代表重复的次数, 第二个参数代表需要重复的值或者模式。

下面例子中第二个参数表示重复的模式。

/* 定义一个5行6列的容器, 项目的宽分别为 50px 100px 150px 50px 100px 150px */

.container {
    display: grid;
    grid-template-columns: repeat(2, 50px 100px 150px);
    grid-template-rows: repeat(5, 100px)
}

auto-fill

当容器的宽度不确定的时候,如果需要容器中尽可能的充满项目,使用 auto-fill 属性自动填充容器。

/* 在容器中产生尽可能多的宽为 100px 的列 */
.container {
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px)
}

minmax(min,max)

给定项目一个长度范围, 使项目的长度在这个范围当中。

如下, 定义一个 4*2 的容器, 控制列的宽度为 100px~200px 之间, 当容器的宽度发生改变时, 列的宽度会响应变化, 变化的区间是 100px~200px

.container {
    display: grid;
    grid-template-columns: repeat(4, minmax(100px, 200px));
    grid-template-rows: 100px 100px;
}

auto

不设定项目的宽度, 由浏览器根据实际情况决定项目的宽

如下, 定义一个 4*2 的容器,第二列的宽度设置为 auto, 当容器的宽度发生改变时, 第二行的宽度将会自动计算,使得四列总是占满一行

.container {
    display: grid;
    grid-template-columns: 100px auto 150px 75px;
    grid-template-rows:repeat(2, 100px)
}

fr 单位

fr 是网格布局提供的一种表示比例关系的关键词, 如果两列的宽度分别为 1fr2fr, 表示后者的宽度是前者宽度的两倍。

/* 定义包含两列的容器, 后者是前者的两倍 */
.container {
    display: grid;
    grid-template-columns: 1fr 2fr;
}

/* 定义包含三列的容器, 第一列的宽度为100px, 剩余部分分为3部分, 第二列占一份, 第三列占两份 */
.container {
    display: grid;
    grid-template-columns: 100px 1fr 2fr;
}

定义网格线的名称

容器中的子项目的分布是由无形的一条条网格线划分的, 在定义行和列的时候可以同时定义网格线的名称,方面设定子项目的位置和跨度。

/* 定义容器布局为 2*2, 因此有3条垂直线和3条水平线, 在方格定义网格线的名称*/
.container {
    display: grid;
    grid-template-columns: [line1] 100px [line2] 100px [line3] 100px [line4];
    grid-template-rows: [line1] 100px [line2] 100px [line3] 100px [line4];
}

grid-column-gap grid-row-gap grid-gap

grid-row-gap 定义行间距 grid-column-gap 定义列间距

/* 定义行间距为 20px 列间距为 10px */
.container {
    display; grid;
    grid-template-columns; repeat(4, 100px);
    grid-template-rows: repeat(2, 100px);
    grid-row-gap: 20px; 
    grid-column-gap: 10px;
}

grid-gap

grid-gapgrid-column-gapgrid-row-gap 的简写

/* 定义行间距为 20px 列间距为 10px */
.container {
    display; grid;
    grid-template-columns; repeat(4, 100px);
    grid-template-rows: repeat(4, 100px);
    grid-gap: 20px 10px;
}

grid-gap 的第二个参数省略时, 表示 grid-row-gapgrid-column-gap 的值相同

/* 定义行间距和列间距都为为 20px */
.container {
    display; grid;
    grid-template-columns; repeat(4, 100px);
    grid-template-rows: repeat(4, 100px);
    grid-gap: 20px;
}

在新标准中可以省略grid-gap、grid-column-gap、grid-row-gap 的 grid 字段, 写为 gap、row-gap、column-gap

grid-template-areas

定义网格区域的名称, 同网格线名称的作用相同,方便定义子项目位置, 跨度的定义.

.container {
    display: grid;
    grid-template-columns: repeat(4, 100px);
    grid-template-rows: repeat(4, 100px);
    grid-template-areas:'a b c'
                        'd f e'
                        'g h i';
}

grid-auto-flow

定义子项目的排列顺序, 默认是先列后行(row), 使用该属性来修改子项目的排列顺序;,接受两种类型的值

column / row 更改子项目的排列顺序, 下图是设置 grid-auto-flow:columns 时的显示。

column dense / row dense 这两个值主要用于某些项目指定位置以后,剩下的项目怎么自动放置。

如下图, 设置一个3*3 的网格布局

更改项目 1 和项目 2 的跨列情况, 由于 2 项目在第一行放不下跑到了第二行, 而原本的位置变为了空。

使用 grid-auto-flow: row dense, 使布局紧凑化, 项目 3 将会往上填充。

另外一种情况是使用 grid-auto-flow: column, 并更改项目 1 和项目 2 的跨行情况

使用 grid-auto-flow: row dense, 使布局紧凑化, 项目 3 将会往左填充。

定义子项目内容的显示

justify-items:定义子项目在水平位置的分布

align-items:定义子项目在垂直位置上面的分布

place-items: justify-items 和 align-items 的合并写法

在之前的项目中内容默认都是在左上角, 通过配置这三个属性来改变;

这三个属性的值的可选项为:

  1. start: 对齐单元格的起始边
  2. end: 对齐单元格的结束边
  3. center: 在单元格居中
  4. stretch: 充满整个单元格

这和 Flex 布局的 justify-contentalign-item 属性的使用是相似的。

默认子项目的内容是居左上角显示,既 justify-items: start; align-items: start

设置项目的内容上下居中显示

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
    gap: 10px;
    justify-items: center;
    align-items: center;
}

使用 place-items 缩写的形式代替上面的写法;

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
    gap: 10px;
    palce-item: center center
}

kustify-itemsalign-items 的值相同时, place-items 可以简写为一个值, 即: place-items: center

设置内容区域在容器中的位置显示

当设置一个元素为容器后,元素变为块级元素, 当这个元素里的列不能占满整行时, 右边部分将会空出来。当然这种情况在高度占不满时依旧存在;

这时候可以通过属性设置改变这种显示

justify-content 设置内容区域在容器中的水平位置显示

align-content 设置内容区域在容器中的垂直位置的显示

place-content 是 align-content 和 jistify-content 两个属性的简写

这三个属性的可选值同为以下7种

    .container {
        display: grid;
        justify-content: start | end | center |  stretch | space-around | space-between | space-evenly;
    }

下面以水平位置显示为例

start 对齐容器的起始边。(默认值)

end 对齐容器的结束边

center 在容器的中间

space-around 每个项目的两侧距离相同

stretch 占满整个容器空间

space-between 项目居两边显示,项目与项目之间的间隔相同。

space-evenly 项目与项目之间,项目与容器边框之间的距离都相同


上面把 Grid 布局的常用属性做了说明, 在是实战项目中以下几点是经常会使用到的: 1. 定义一个容器 dispaly: grid / inline-grid 2. 设置行和列 grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px) 3. 设置单元格内容位置显示 place-items: center 4. 设置容器内容位置显示 place-content: center

除了上述讲到的属性外, 容器上还有一个属性可以配置行和列超出配置的限制后的显示grid-auto-columns(超出列的显示) grid-auto-rows(超出行的显示), 后跟行和列的高和宽。

子项目属性

设置子项目的行或列的跨度

在配置子项目的跨度时,把子元素拆分为四条边来配置,这无疑能帮助更快掌握下边四个属性的要点

grid-column-start 设置项目左边框的位置

grid-column-end 设置项目右边框的位置

grid-row-star 设置项目上边框的位置

grid-row-end 设置项目下边框的位置

行或列边框在未定义的情况下从1开始递增

下面设置 项目1 的上下左右边框的位置分别为 1、3、1、3

.box-item {
    grid-row-start: 1; 
    grid-row-end: 3;
    grid-column-start: 1;
    grid-column-end: 3;
}

定义项目边框的位置并不一定是上下、左右成对出现的, 当只定义了一边时, 另外一边将根据 grid-zuto-flow 属性自动设定

使用自定义的网格线

在定义容器属性时可以同时定义网格线:

.container {
    display: grid;
    grid-template-columns: [l1] 100px [l2] 100px [l3] 100px [l4];
    grid-template-rows: [r1] 100px [r2] 100px [r3] 100px [r4];
}

这是定义子项目的起始边框位置时可以使用自定义网格线的名称。

.box-item {
    grid-row-start: r1; 
    grid-row-end: r3;
    grid-column-start: l1;
    grid-column-end: l3;
}

这种定义的方式和上面使用默认网格线的名称结果相同

使用 span 关键词

无疑每次定义四个属性才能定义单元格的边框位置是复杂的,下面展示了使用 span 关键词来重写上面的效果

.box-item {
    grid-row-start: span 2; 
    grid-column-start: span 2;
}

上面的代码中 span 可以理解为 跨越, span 2 表示跨越2个网格。***span 的跨越位置是当前子项目默认的边框线。

当然 span 并不只是向后或先下跨越网格,当把 grid-row/column-start 改为 grid-row/column-end 时, span 便表示向左/上 跨越

下面这段代码和上面的代码效果是相同的。

.box-item {
    grid-row-end: span 2; 
    grid-column-end: span 2;
}

grid-column/grid-row

grid-column属性是grid-column-startgrid-column-end的合并简写形式, grid-row属性是grid-row-start属性和grid-row-end的合并简写形式。

.item-1 {
  grid-column: 1 / 3;
  grid-row: 1 / 2;
}
/* 等同于 */
.item-1 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

这两个属性之中,也可以使用span关键字,表示跨越多少个网格。

.item-1 {
  background: #b03532;
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
/* 等同于 */
.item-1 {
  background: #b03532;
  grid-column: 1 / span 2;
  grid-row: 1 / span 2;
}

grid-area 属性

在定义容器属性时可以定义网格区域:

.container {
    display: grid;
    grid-template-columns: repeat(3, 100px);
    grid-template-rows: repeat(3, 100px);
    grid-template-areas:'a b c'
                        'd f e'
                        'g h i';
}

在定义子元素的位置时, 可以使用已经定义好的网格区域名称快速定义子项目的分布位置。

/* 把子元素放在 f 区间 */
.box-item {
    grid-area: f
}

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

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

justify-self/align-self/place-self

justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。 align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目。 place-self属性是align-self属性和justify-self属性的合并简写形式。