## 网格布局详解 设置样式`display:grid`或`display:inline-grid`可以触发网格布局。相对于一维的弹性弹性布局,网格布局提供了更加强大的二维布局能力。 在介绍网格布局的各种能力之前,我们先通过下图明确一下行(`row`),列(`column`),格子区域(`area`)和间隔(`gap`)等概念。 ![](https://img.kancloud.cn/ea/c7/eac7ce459f53b60cb190170812cb92ef_520x244.png) 如图,“1”,“2”这样横向可以占满整个容器水平方向的称为一行, “1”,“3”,“5”这样可以纵向占满容器垂直方向的称为一列。“1”,“2”,“3”,“4”,“5”,“5”每个灰色区域称为一个格子区域,“1”和“2”之间的白色称为行间隔(`row-gap`), “1”和“3”质检的白色间隔称为列间隔(`column-gap`),行间隔和列间隔统称为间隔。 代码如下: ```html <style> .grid{ display: grid; width: 500px; grid-template-columns: 1fr 1fr 1fr; grid-gap: 20px 10px; grid-template-areas: 'a b b' 'c . d' 'e f g'; } .grid>*{ border:1px solid #ccc; height: 60px; background: #f8f8f8; } </style> <div class='grid'> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> <div style="grid-area: d;">4</div> <div style="grid-area: e;">5</div> <div style="grid-area: f;">6</div> </div> ``` ### grid-template-columns 该属性定义了列数以及每列的宽度,这里除了我们常用的单位(如`px`,`%`,`em`等)之外,还可以使用`fr`单位, 也可以使用`auto`(根据所在列最长元素决定该列的宽度)。 类似flex的`flex-grow`, `fr`单位定义的是对剩余空间的分配比例,但是剩余空间分配的计算方法相对简单,完全按照比例分配,因为该布局方式不存在类似`flex-basis`的基准宽度。但是如果剩余可分配空间小于元素本身的宽度的话,元素将会溢出到容器之外,该列元素保持自身的宽度,不会伸缩。 ![](https://img.kancloud.cn/a2/5e/a25e3e101885e953db20ca5a9eb6d896_206x84.png) 如图,容器宽度为200,“1”的宽度时40,两个间隔分别是10,“2”,“3”剩余可分配空间是200-40-2*10=140, 那么“2”的宽度是140*1/3=46.67, “3”的宽度时140*2/3=93.33. css代码如下: ```css .grid{ display: grid; width:200px; grid-gap: 10px; grid-template-columns: 40px 1fr 2fr; } .grid>*{ border:1px solid #ddd; background: #eee; height:30px; } ``` #### repeat(times, width)函数 该函数定义`grid-template-columns`和`grid-template-rows`中定义空间按照指定宽度重复三次,其中times指重复次数,可选值是大于0的数字和`auto-fill`(不指定次数,根据子元素宽度自动排列,超出就换行,此时宽度width不能是fr单位),最小值是1;width需要重复的每列的宽度(或每行的高度),也可以使用fr单位。例如:`grid-template-columns: 40x repeat(2, 1fr)`和`grid-template-columns: 40x 1fr 1fr`是等价的。 ![](https://img.kancloud.cn/29/2e/292e9dd1204544be6d6e8fadb50fd04b_193x84.png) ```css .grid{ width:200px; grid-template-columns: 40px repeat(auto-fill, 60px); } ``` #### minmax(min, max)函数 该函数定义的是一列的宽度范围,max小于min时,该值等于min.设置`grid-template-columns: 40px minmax(80px,150px) 1fr `的元素在不同宽度下结果如下: ![](https://img.kancloud.cn/c3/de/c3de17d4e428346b1c052bf502345ecf_317x172.png) ### grid-template-rows 该属性定义的各行的高度,与`grid-template-columns`不同的是,该属性不定义行的数量。如果行数超出该属性定义的行数,那么,超出部分按照该行最高元素来定义行高度。 ![](https://img.kancloud.cn/c1/c3/c1c3207cfc44dcbf8d3c1bb692e3b054_210x210.png) ```css width: 200px; height: 200px; grid-gap: 10px; grid-template-columns: repeat(3, 1fr); grid-template-rows: 30px repeat(2, 1fr); ``` ### grid-area 和 grid-template-areas `grid-area`用于子元素定义子元素的名称。 `grid-template-areas`使用子元素定义的名称进行布局,布局时可以进行跨行、跨列或者网格区域留空。 该属性的写法为每行用引号(单双均可)引起来,每列之间用空格区分,每行的列数必须一致,跨行则在同一行相邻位置重复使用相应的网格区域名称,跨列则在同一列相邻位置使用相同的网格区域名称,区域留白则使用小圆点(.)代替区域名称。 ![](https://img.kancloud.cn/66/83/6683535ef2733bd05604112952bfac0c_519x87.png) 代码如下: ```html <div class='grid' style="grid-template-areas:'a b''c d'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> <div style="grid-area: d;">4</div> </div> <div class='grid' style="grid-template-areas:'a a''b c'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> </div> <div class='grid' style="grid-template-areas:'a b''a c'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> </div> <div class='grid' style="grid-template-areas:'a .''b c'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> </div> ``` 经实验可知,以下值得设置方式会导致`grid-template-areas`失效: 1. 斜跨列和行,即需要跨行(或跨列)的网格区域未定义在相邻的行(或列)。例如上图第一个网格设置成`'a b''c a'`. 2. 存在声明的区域网格名称不存在。例如上图第一个网格设置成`'a b''c e'`. 3. 不是所有行的列数都一致。例如上图第一个网格设置成`'a b''c'`. 如果,子元素中存在相同名称的网格区域,那么后者将会覆盖前者。 如果,存在留白的网格区域,而存在子元素未声明网格区域名称,那么未声明网格区域名称的元素就将会填充到留白的网格区域。 如果,子元素中存在定义了区域网格名称,但是未引用的话,整个容器形成一种比较诡异的展现形式。 ![](https://img.kancloud.cn/80/33/80330319840855734763b7fc8ddb9afc_385x155.png) ```html <div class='grid' style="grid-template-areas:'a b''c d'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> <div style="grid-area: d;">4</div> <div style="grid-area: d;">5</div> </div> <div class='grid' style="grid-template-areas:'a .''b c'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> <div>4</div> <div>5</div> </div> <div class='grid' style="grid-template-areas:'a b''. c'"> <div style="grid-area: a;">1</div> <div style="grid-area: b;">2</div> <div style="grid-area: c;">3</div> <div style="grid-area: d;">4</div> <div style="grid-area: e;">5</div> </div> ``` **注意:** 如果在一个元素里同时定义了`grid-template-areas`和`grid-template-columns`且在列数方面有冲突,那么是后定义的覆盖前面定义的,但是如果`grid-template-columns`用到了`auto-fill`, 那么`grid-template-columns`将会无效。