CSS布局新方案——Grid 网格布局

来源:互联网 发布:淘宝手机海报尺寸2017 编辑:程序博客网 时间:2024/05/17 06:41

CSS Grid 是一个基于二维网格布局的系统,虽然目前浏览器支持并不理想,但是今年3月份之后,各大主流浏览器都发布了对CSS Grid的支持,还是很有必要去学习下的

这里写图片描述

在Web Page Layout 的演进历史中,我们从刚开始的 table 到 float、position、inline-block,再到css3的盒子模型Flexbox。Flexbox已经可以帮助我们解决好多布局的烦恼,我在工作中会经常用到

这里写图片描述

虽然Flexbox可以起到一定的补救作用,但是它只可以实现简单的一维布局,并不适用于复杂的二维布局(实际上 Flexbox 和 Grid 可以一起结合使用起到最佳效果)。网格是 CSS 第一次专门创建的模块,用来解决我们之前在制作网站时使用hacks处理布局问题。

Grid 术语

网格容器(Grid Container)

这个类似于Flexbox里面的Flex容器

一个元素添加 display: grid 属性后,它就成为了一个网格容器

网格项目(Grid Item)

网格容器中的子元素就叫网格项目

<div class="grid-container">    <div class="grid-item"></div>    <div class="grid-item"></div>    <div class="grid-item"></div>    <div class="grid-item"></div></div>

这里的 div.grid-container 是网格容器,div.grid-item 是网格项目

网格线(Grid Line)

网格轨道(Grid Track)

网格单元格(Grid Cell)

网格区域(Grid Area)

容器属性

1. display

定义一个元素成为网格容器,并对其内容建立一个网格格式的上下文。

  • grid:定义一个块级网格

  • inline-grid:定义一个内联级网格

注意: 定义为网格容器后,column, float, clear, 和 vertical-align 元素对网格容器不起作用

2. grid-template-rows 和 grid-template-columns

通过一组值来定义网格的行和列,值得大小代表轨道的大小

属性值:

  • <track-size>:可以是一个长度值(px em等)、百分比或者是网格中自由空间的一部分(fr为单位,类似于Flexbox里面的 flex-basis 的值)

  • <line-name>:你选择的任意名称

  • subgrid:如果你的网格容器本身就是一个网格项(即嵌套网格),你可以使用此属性指定行和列的大小继承于父元素而不是自身指定(一般很少会用)

.container{     grid-template-columns: <track-size> ...;    grid-template-columns: <line-name> <track-size> ...;    grid-template-columns: subgrid;}

示例:

<div class="grid-container">    <div class="grid-item item1">1</div>    <div class="grid-item item2">2</div>    <div class="grid-item item3">3</div>    <div class="grid-item item4">4</div>    <div class="grid-item item5">5</div>    <div class="grid-item item6">6</div>    <div class="grid-item item7">7</div>    <div class="grid-item item8">8</div></div>
<style>    .grid-container {        display: grid;        width: 600px;        height: 600px;        grid-template-columns: 1fr 1fr 1fr;        grid-template-rows: 25% 250px auto;    }    .grid-item {        background: #05EDB7;    }    .grid-item {        border: 1px solid #4B8BF5;        font-size: 20px;        color: #fff;    }</style>

这里写图片描述

可以看到,网格容器被 grid-template-columns grid-template-rows 分成了三列三行,列通过 1fr 1fr 1fr 分成了等宽的三份,项目默认会充满单元格。

这里如果 <track-size> 有连续重复的值,可以使用 repeat()

grid-template-columns: 1fr 1fr 1fr;

等价于:

grid-template-columns: repeat(3, 1fr);

3. grid-template-areas

属性值:

  • <grid-ara-name>:网格区域名称
  • .:空单元格
  • none:无网格区域被定义

将这个网格容器划分成几个区域,从而组成一个网格模板,这几个区域有各自的名称,子项目通过 grid-area 属性来占有相应的区域。这个我觉得和vue里面的slot具名插槽有点类似,下面看一个例子:

<div class="grid-container">    <div class="grid-item item1">header</div>    <div class="grid-item item2">main</div>    <div class="grid-item item3">slidebar</div>    <div class="grid-item item4">footer</div></div>
<style>    .grid-container {        display: grid;        width: 600px;        height: 600px;        grid-template-columns: repeat(4, 1fr);        grid-template-rows: auto;        grid-template-areas: "header header header header"                             "main main . slidebar"                             "footer footer footer footer"    }    .grid-item {        font-size: 20px;        color: #fff;    }    .item1 {        background: #05EDB7;        grid-area: header;    }    .item2 {        grid-area: main;        background: #4C8CF5;    }    .item3 {        grid-area: slidebar;        background: #F1F962;    }    .item4 {        grid-area: footer;        background: #F97F78;    }</style>

这里写图片描述

你可以看到是不是和slot有些类似

另外这里用 . 表示一个空的单元格。

注意: 这里命名的网各区域的同时,区域两边的网格线会自动得到命名,比如上面的:header-start header-end

4. grid-column-gap 和 grid-row-gap

从gap的意思就可以看出来,这两个属性是用来设置间隙(两者之间,不包括边缘)的大小,也就是轨道与轨道之间网格线的大小,可以理解为行/列之间设置的margin大小。

属性值:

  • <gap-size>:一个长度值

示例:

<div class="grid-container">    <div class="grid-item item1">1</div>    <div class="grid-item item2">2</div>    <div class="grid-item item3">3</div>    <div class="grid-item item4">4</div>    <div class="grid-item item5">5</div>    <div class="grid-item item6">6</div>    <div class="grid-item item7">7</div>    <div class="grid-item item8">8</div>    <div class="grid-item item9">9</div></div>
.grid-container {    display: grid;    width: 600px;    height: 600px;    grid-template-columns: repeat(3, 1fr);    grid-template-rows: repeat(3, 1fr);    grid-row-gap: 20px;    grid-column-gap: 10px;}.grid-item {    background: #05EDB7;    font-size: 20px;    color: #fff;}

这里写图片描述

5. grid-gap

grid-gapgrid-row-gapgrid-column-gap 的复合属性,注意先是行再是列:

grid-gap: 20px 10px;// 等价于:grid-row-gap: 20px;grid-column-gap: 10px;

如果只有一个值,就是两者相同。

6. justify-items

定义 所有网格项 相对于 列轴 在水平方向上的对齐方式

属性值:

  • start :项目与网格轨道的左端对齐
  • end:项目与网格轨道的右端对齐
  • center:在项目所在轨道居中对齐
  • stretch:项目宽度占据整个单元格区域(默认值,前提是项目没有设置宽度)

示例:

justify-items: center 为例,这里一些项目设置了宽度,可见没有设置宽度的项目(3和7)宽度没有充满单元格:

这里写图片描述

7. align-items

justify-items 相对应的,网格项目在所在的 行轨道 上的对齐方式,属性值同样和列对齐是一样的:

  • start:项目与行轨道顶端对齐
  • end:项目与行轨道底端对齐
  • center:项目与行轨道居中=对齐
  • stretch:项目高度占据整个单元格区域(默认值,前提是项目没有设置高度,从上面的例子可以看出)

8. justify-content

定义网格列宽的时候,当你使用 px 之类的非响应式长度单位,并且网格大小小于网格容器的时候,这种情况下可以设置网格之间的对齐方式。justify-content 就是设置网格在y轴上的对齐方式,就像下面的例子:

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: 80px 120px 80px;    grid-template-rows: auto;    grid-gap: 10px;    /*justify-content: center;*/}.grid-item {    background: #05EDB7;    font-size: 20px;    color: #fff;}

这里通过 grid-template-columns: 80px 120px 80px; 定义了 80px120px80px 三列的网格,但是网格容器是600px,现在就可以设置网格之间的对齐方式,初始的时候是下面的样子,可以看到有一部分空白:

这里写图片描述

现在来看下 justify-content 的属性值:

  • start:网格在网格容器中左对齐

这里写图片描述

  • end:网格在网格容器中右对齐

这里写图片描述

  • center:网格在网格容器中居中对齐

这里写图片描述

  • stretch:调整网格的大小,使其宽度填充整个网格容器(这个我设置了但还是没什么作用,和start是一样的效果,不知道是不是理解错了)

  • space-around:和Flexbox里面的是一样的道理,设置网格左右两边的边距相等

这里写图片描述

  • space-between:和Flexbox里面的是一样的道理,两端对齐,也就是网格与网格之间的距离相等,左右边缘的网格贴边

这里写图片描述

  • space-evenly:正如 evenly 的意思一样,平均分配空白区域,使网格之间以及边缘的网格到边缘的距离都相等。为了模拟这个,先把 grid-gap 值设为0,可以从下图看到空白被等分了

这里写图片描述

9. align-content

这个和上面的 justify-content 道理是一样的,不过 align-content是网格在 垂直 方向上的对齐方式自动生成,就不做介绍了

10. grid-auto-columns 和 grid-auto-rows

指定任何自动生成的网格轨道(隐式网格)的大小。当显示定位行与列(使用 grid-template-columns/grid-template-rows属性)时候,如果网格项目超出了网格的定义范围,那么就会创建隐式网格。

属性值:

  • <track-size>:可以是长度、百分比、或网格自由空间的一部分(以fr为单位)

示例:

创建一个两列两行的网格

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: 100px 100px;    grid-template-rows: 100px 100px;}

定义两个网格项:

.item1 {    grid-column: 1 / 2;    grid-row: 2 / 3;}.item2 {    grid-column: 5 / 6;    grid-row: 2 / 3;}

两列两行的网格,网格线编号是从1到3,而网格项item3定义起始列线5到终止列线6之间的区域,这超出了定义范围,如图所示:

这里写图片描述

因为引用了不存在的网格线,所以会自动创建隐式轨道来填补空白。这时候就可以使用 grid-auto-columnsgrid-auto-rows 来设置隐式轨道的宽度:

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: 100px 100px;    grid-template-rows: 100px 100px;    grid-auto-columns: 1fr;}

这里写图片描述

11. grid-auto-flow

这个属性,当我们没有显示地在网格中放置网格项,这时候自动布局会自动帮助我们排列网格项,使用grid-auto-flow 可以更改自动排列的方式。

属性值:

  • row:自动布局会将没有定义位置的网格项填充每一行,必要时添加新行(默认)
  • column:自动布局会将没有定义位置的网格项填充每一列,必要时添加新列
  • row dense/column dense:如果按照row或者column排列的话出现空白,设置dense自动布局会试图填充空白

示例:

如图所示,定义一个5列5行的网格,这里并没有定义网格项的大小,可以看到,默认是填每一行,即 row

这里写图片描述

现在我们来调整 item7 的区域大小:

.item7 {    grid-column: span 2;    grid-row: span 2;}

如下图所示,其他的网格项会自动填充每一行:

这里写图片描述

如果 grid-auto-flow 的值改为 column 是同样的道理:

这里写图片描述

现在回到默认的 row,再改变 item9 的大小:

.item9 {    grid-column: span 2;    grid-row: span 2;}

会变成下图所示的效果:

这里写图片描述

item9被换到了新的一行,这时候item8傍边以及item6下面会出现空白,看着很是别扭,这时候就需要用到 dense

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: repeat(5, 1fr);    grid-template-rows: repeat(5, 1fr);    grid-gap: 2px;    grid-auto-flow: row dense;}

这里如果是按照行来排列的话 row 可以省略,因为默认是 row;如果是按列来排列的,就需要写为:grid-auto-flow: column dense

这里写图片描述

12. grid

这是一个复合属性,可以设置 grid-template-rowsgrid-template-columnsgrid-template-areasgrid-auto-rows +、grid-auto-columns 以及 grid-auto-flow

grid = grid-template-columns + grid-template-rows + grid-template-areas + grid-auto-rows + grid-auto-columns + grid-auto-flow

属性值:

  • none:将所有的子属性设置为初始值
  • subgrid:将 grid-template-rowsgrid-template-columns 的值设置为 subgrid(继承来自父元素的设置),其余子属性值为初始值
  • <grid-template-rows>/<grid-template-columns>:将这两个属性的值设置指定值,其余的子属性值为初始值
  • <grid-auto-flow>[<grid-auto-rows> [/<grid-auto-columns>]]:这三个属性分别接受相同的值,如果省略了 grid-auto-columns 属性,它将设置为 grid-auto-rows 属性的值。如果两个都被忽略,那么都将设置为初始值。

示例:

grid: 100px auto / repeat(3, 1fr);// 等价于:grid-template-rows: 100px auto;grid-template-columns: 1fr auto 1fr;grid-template-areas: none;
grid: column 1fr / auto;// 等价于:grid-auto-flow: column;grid-auto-rows: 1fr;grid-auto-columns: auto;
// 一次设置 `grid-template-areas` `grid-template-rows` `grid-template-columns`grid: [row1-start] "header header header" 1fr [row1-end]      [row2-start] "footer footer footer" 200px [row2-end]      / auto 50px auto;// 等价于:grid-template-areas: "header header header"                     "footer footer footer";grid-template-rows: [row1-start] 1fr [row1-end row2-start] 200px [row2-end];grid-template-columns: auto 50px auto;

网格项目的属性

1. grid-column-start/grid-column-end/grid-row-start/grid-row-end

用网格线来包围出一片区域来定义网格项在网格容器中的位置

属性值:

  • <line>:可以是一个数字来引用对应编号的网格线,或者是你在定义 grid-template-... 时候定义的网格线名称。
  • span <number>:网格项区域所跨的网格轨道的数量
  • span <name>:网格项包含指定名称网格项的网格线之前的网格轨道(这个我感觉和直接使用<name>是一样的啊,没什么区别)
  • auto:自动定位

示例:

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: 1fr [col2-start] 1fr [col2-end col3-start] 1fr [col3-end col4-start] 1fr [col-end];    grid-template-rows: 1fr [row2-start] 1fr [row2-end col3-start] 1fr [row3-end row4-start] 1fr [col-end];    justify-content: stretch;}.grid-item {    background: #05EDB7;    font-size: 20px;    color: #fff;}.item1 {    grid-column-start: 1;    grid-column-end: span col4-start;    grid-row-start: 1;    grid-row-end: span 3;}

这里写图片描述

如果没有声明 grid-column-end/grid-row-end,默认情况下网格项的跨度是 1。
网格项可以互相重叠,使用 z-index 设置层级顺序

2. grid-column/grid-row

grid-column = grid-column-start + grid-column-end

grid-row = grid-row-start + grid-row-end

属性值:

  • <start-line> / <end-line>:可以是跨度或者网格线

示例:

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: 1fr [col2-start] 1fr [col2-end col3-start] 1fr [col3-end col4-start] 1fr [col-end];    grid-template-rows: 1fr [row2-start] 1fr [row2-end col3-start] 1fr [row3-end row4-start] 1fr [col-end];    justify-content: stretch;}.grid-item {    background: #05EDB7;    font-size: 20px;    color: #fff;}.item1 {    grid-column: 1 / col4-start;    grid-row: 1 / span 3;}

这里写图片描述

同样的,如果只用一个值,也就是没有声明结束的网格线,默认的轨道跨度为 1

3. grid-area

这个在上面已经提到过,网格容器通过属性 grid-template-areas 定义网格模板,每个区域定义自己的名称,然后网格项通过 属性grid-area 来选择自己区域,就像填色一样。

如果网格容器没有定义模板,那么这个属性相当于 grid-columngrid-row的和,也就是由四个值组成

属性值:

  • <name>:区域的名称
  • <row-start>/<column-start>/<row-end>/<column-end>:四个值组成,可以是数字或者名称,要注意顺序

示例:

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: 1fr [col2-start] 1fr [col2-end col3-start] 1fr [col3-end col4-start] 1fr [col-end];    grid-template-rows: 1fr [row2-start] 1fr [row2-end col3-start] 1fr [row3-end row4-start] 1fr [col-end];    justify-content: stretch;}.grid-item {    background: #05EDB7;    font-size: 20px;    color: #fff;}.item1 {    grid-area: 2 / 1 / row4-start / 3}

这里写图片描述

4. justify-self

定义 某个网格项 相对于所在的列轴在水平方向上的对齐方式(可以定义某个网格项不同于 使用 justify-items 的对齐方式)

属性值:

  • start:网格项在所在网格区域左对齐
  • end:网格项在所在网格区域右对齐
  • center :居中对齐
  • stretch:网格项宽度占据整个网格区域(默认,前提是项目没有设置宽高)

示例:

.grid-container {    display: grid;    width: 400px;    height: 400px;    border: 1px solid #F97F78;    grid-template-columns: repeat(3, 1fr);    grid-template-rows: repeat(3, 1fr);    grid-gap: 5px;    justify-items: start;}.grid-item {    width: 50px;    height: 50px;    background: #05EDB7;    font-size: 20px;    color: #fff;}
  • start
.item1 {    justify-self: start;}

这里写图片描述

  • end
.item1 {    justify-self: end;}

这里写图片描述

  • center
.item1 {    justify-self: center;}

这里写图片描述

5. align-self

定义 某个网格项 相对于行轴在垂直方向上的对齐方式(可以定义某个网格项不同于 使用 align-items 的对齐方式)

引用文章

CSS Grid布局这样玩

CSS Grid布局指南