css

display: grid;网格布局

Posted by Jxx on April 1, 2019

一、前言

网格是一组相交的水平线和垂直线,它定义了网格的列和行。我们可以将网格元素放置在与这些行和列相关的位置上。 CSS网格布局引入了二维网格布局系统,可用于布局页面主要的区域布局或小型组件。

二、网格容器

<div>这类块级元素设置 display:grid 或给<span>这类内联元素设置 display:inline-grid 来创建一个网格容器。一旦我们这样做,这个元素的所有直系子元素将成为网格元素,Grid布局即创建。

在下面这个例子中,这有一个类名为 wrapper 的div 元素作为容器 ,它内部有五个子元素。

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>

将div.wrapper 作为一个网格容器,它的所有直系子元素将成为网格元素。

.wrapper {
  display: grid;
}

效果图:
grid

在CodePan中打开

在Grid布局中,所有相关CSS属性正好分为两拨,一拨作用在grid容器上,还有一拨作用在grid子项上。具体参见下表:

作用在grid容器上 作用在grid子项上

三、作用在grid容器上的CSS属性

1. grid-template-columnsgrid-template-rows

grid-template-columnsgrid-template-rows分别定义网格的列和行,一个网格轨道就是网格中任意两条线之间的空间。

语法:

.wrapper {
  grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
  grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
}
  • <track-size>:单元网格的尺寸。可以是长度值,百分比值,以及fr单位(网格容器中可用空间的一等份)。
  • <line-name>:网格线的名字,可以任意命名。

fr:是单词fraction的缩写,表示分数。

fr单位代表网格容器中可用空间的一等份。

repeat():用来重复部分或整个轨道列表

例如网格:它起始轨道为20像素,接着重复了6个1fr的轨道,最后再添加了一个20像素的轨道

.wrapper {
  display: grid;
  grid-template-columns: 20px repeat(6, 1fr) 20px;
}

又如网格 :有共计10个轨道,1个1fr轨道后面跟着1个2fr轨道,该模式重复5次

.wrapper {
  display: grid;
  grid-template-columns: repeat(5, 1fr 2fr);
}

minmax()函数

设置自动创建的行高或者列宽最小值和最大值

例:自动创建的行高将会是最小100像素,最大为auto

grid-auto-rows: minmax(100px, auto);

2. grid-template-areas

通过引用 grid-area 属性指定的 网格区域(Grid Area) 名称来定义网格模板。重复网格区域的名称导致内容跨越这些单元格。一个点号(.)代表一个空单元格。这个语法本身可视作网格的可视化结构。

语法:

.wrapper {
  grid-template-areas: 
    "<grid-area-name> | . | none | ..."
    "...";
}
  • <grid-area-name>:由网格项的 grid-area 指定的网格区域名称
  • .(点号) :代表一个空的网格单元
  • none:不定义网格区域

例如:
html代码:

<div class="wrapper">
  <div class="putao">葡萄种植区</div>
  <div class="longxia">龙虾养殖区</div>
  <div class="yangyu">鱼类养殖区</div>
  <div class="xigua">西瓜种植区</div>
</div>

css代码:

/*grid容器*/
.wrapper {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr 1fr;
    grid-template-areas: 
        "葡萄 葡萄 葡萄"
        "龙虾 养鱼 养鱼"
        "龙虾 养鱼 养鱼"
        "西瓜 西瓜 西瓜";
}
/*grid子项*/
.putao { grid-area: 葡萄; }
.longxia { grid-area: 龙虾; }
.yangyu { grid-area: 养鱼; }
.xigua { grid-area: 西瓜; }

效果图:
grid

在CodePan中打开

3. grid-template

grid-template 是一个简写的CSS属性,用于定义 grid-template-rowsgrid-template-columnsgrid-template-areas属性。

语法:

.wrapper {
    grid-template: none / <string>+;
}
/*即:*/
.wrapper {
    grid-template: none;
}
.wrapper {
    grid-template: <grid-template-rows> / <grid-template-columns>;
}
  • none:表示将3个CSS属性都设置为初始值。
  • <string>+:每一个给定的字符串会生成一行,一个字符串中用空格分隔的每一个单元(cell)会生成一列。多个同名的,跨越相邻行或列的单元称为网格区块(grid area)。非矩形的网格区块是无效的

例如:css代码:

.wrapper {
    grid-template-areas: "head head"
                           "nav  main"
                           "nav  foot";
    grid-template-rows: 50px 1fr 30px;
    grid-template-columns: 150px 1fr;
}
/*等同于*/
.wrapper {
    grid-template: "head head" 50px
                   "nav  main" 1fr
                   "nav  foot" 30px 
                    / 150px 1fr;
}

效果图:
grid

在CodePan中打开

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

grid-column-gapgrid-row-gap属性用来定义网格中网格间隙的尺寸。

语法如下:

.wrapper {
  grid-column-gap: <line-size>;
  grid-row-gap: <line-size>;
}
  • <line-size>:网格间的间隙尺寸。

5. grid-gap(gap)

grid-gap属性是grid-column-gap和grid-row-gap属性的缩写。语法如下:

.wrapper {
    grid-gap: <grid-row-gap> <grid-column-gap>;
}

先横row后竖column

CSS Grid Layout 起初是用 grid-gap 属性来定义的,目前逐渐被 gap 替代。但是,为了兼容那些不支持 gap 属性的浏览器,你需要像上面的例子一样,使用带有前缀的属性。

6. justify-items

justify-items指定了网格元素的水平呈现方式,是水平拉伸显示,还是左中右对齐,语法如下:

.wrapper {
    justify-items: stretch | start | end | center;
}
  • stretch:默认值,拉伸。表现为水平填充。
  • start:表现为网格水平尺寸收缩为内容大小,同时沿着网格线左侧对齐显示(假设文档流方向没有变)。
  • end:表现为网格水平尺寸收缩为内容大小,同时沿着网格线右侧对齐显示(假设文档流方向没有变)。
  • center:表现为网格水平尺寸收缩为内容大小,同时在当前网格区域内部水平居中对齐显示(假设文档流方向没有变)。

7. align-items

align-items指定了网格元素的垂直呈现方式,是垂直拉伸显示,还是上中下对齐,语法如下:

.wrapper {
    align-items: stretch | start | end | center;
}

其中(假设文档流方向为网页默认):

  • stretch:默认值,拉伸。表现为垂直填充。
  • start:表现为网格垂直尺寸收缩为内容大小,同时沿着上网格线对齐显示。
  • end:表现为网格垂直尺寸收缩为内容大小,同时沿着下网格线对齐显示。
  • center:表现为网格垂直尺寸收缩为内容大小,同时在当前网格区域内部垂直居中对齐显示。

8. place-items

place-itemsalign-itemsjustify-items的缩写(如果有兼容性顾虑,建议还是分开书写)。语法如下:

.wrapper {
    place-items: <align-items> / <justify-items>;
}

align-items在前,justify-items在后

9. justify-content

justify-content指定了网格元素的水平分布方式。此属性仅在网格总宽度小于grid容器宽度时候有效果。例如,我们网格设定的都是固定的宽度值,结果还有剩余空间。例如:

.wrapper {
    display: grid;
    width: 300px;
    grid-template: 100px 100px/100px 100px;
}

此时,水平和垂直方向都有100px的剩余,justify-content属性此时就有用武之地了。

语法如下:

justify-content: stretch | start | end | center | space-between | space-around | space-evenly;

其中:

  • stretch:默认值。拉伸,宽度填满grid容器,拉伸效果需要网格目标尺寸设为auto时候才有效,如果定死了宽度,则无法拉伸。
  • start:默认值。逻辑CSS属性值,与文档流方向相关。默认表现为左对齐。
  • end:逻辑CSS属性值,与文档流方向相关。默认表现为右对齐。
  • center:表现为居中对齐。
  • space-between:表现为两端对齐。between是中间的意思,意思是多余的空白间距只在元素中间区域分配。使用抽象图形示意如下:
    space-between分布效果示意

  • space-around:around是环绕的意思,意思是每个flex子项两侧都环绕互不干扰的等宽的空白间距,最终视觉上边缘两侧的空白只有中间空白宽度一半。使用抽象图形示意如下: space-around分布效果示意

  • space-evenly:evenly是匀称、平等的意思。也就是视觉上,每个flex子项两侧空白间距完全相等。使用抽象图形示意如下: space-evenly分布效果示意

10. align-content

align-contentjustify-content相似且对立的属性,justify-content指明水平方向grid子项的分布方式,而align-content则是指明垂直方向每一行grid元素的分布方式。

语法如下:

align-content: stretch | start | end | center | space-between | space-around | space-evenly;
  • stretch:默认值。每一行flex子元素都等比例拉伸。例如,如果共两行flex子元素,则每一行拉伸高度是50%。
  • start:逻辑CSS属性值,与文档流方向相关。默认表现为顶部堆砌。
  • end:逻辑CSS属性值,与文档流方向相关。默认表现为底部堆放。
  • center:表现为整体垂直居中对齐。
  • space-between:表现为上下两行两端对齐。剩下每一行元素等分剩余空间。
  • space-around:每一行元素上下都享有独立不重叠的空白空间。
  • space-evenly:每一行元素都完全上下等分。

11. place-content

place-contentalign-contentjustify-content的缩写(如果有兼容性顾虑,建议还是分开书写)。语法如下:

.wrapper {
    place-items: <align-content> / <justify-content>;
}

这里顺序是align-content在前,justify-content在后。

如果第二个值不存在,则第一个值用于两者,前提是它是两者的有效值。如果它对一个或另一个无效,则整个值将无效。

12. grid-auto-columns和grid-auto-rows

指定任何自动生成的网格轨道(也称为隐式网格轨道)的大小。 当网格项目多于网格中的单元格或网格项目放置在显式网格之外时,将创建隐式轨道。

语法如下:

.wrapper {
    grid-auto-columns: <track-size> ...;
    grid-auto-rows: <track-size> ...;
}
  • <track-size>:网格中轨道的尺寸。可以是长度值,百分比值,以及fr单位(网格剩余空间比例单位)。

例:用 grid-auto-rows 属性来确保在隐式网格中创建的轨道是200像素高。

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>
<style>
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
}
</style>

效果图:
grid

在CodePan中打开

13. grid-auto-flow

grid-auto-flow属性控制没有明确指定位置的grid子项的放置方式。比方说定义了一个5*2的10格子,共有5个元素,其中2个元素指定了放在哪个格子里,还有3个则自生自灭排列。此时,这3个元素如何排列就是由grid-auto-flow属性控制的。

语法如下:

.wrapper {
  grid-auto-flow: row | column | row dense | column dense
}
  • row:默认值。没有指定位置的网格依次水平排列优先,在必要时增加新行。
  • column:没有指定位置的网格依次垂直排列优先,在必要时增加新列。
  • dense:dense这个英文是稠密的意思。如果有设置,则表示自动排列启用“密集”打包算法。如果稍后出现的网格比较小,则尝试看看前面有没有合适的地方放置,使网格尽可能稠密紧凑。此属性值仅仅改变视觉顺序,会导致DOM属性和实际呈现顺序不符合,这对于可访问性是不友好的,建议谨慎使用。

14. grid

是下面所有这些CSS属性的缩写集合,grid-template-rows,grid-template-columns,grid-template-areas,grid-auto-rows,grid-auto-columns和grid-auto-flow。

语法如下:

  • grid: none
    none表示设置所有的子属性为初始值。

  • grid: <grid-template>
    和grid-template用法一致。例如这样:
    .wrapper {
      grid: 100px 300px / 3fr 1fr;
    }
    /*等同于下面:*/
    .wrapper {
      grid-template-rows: 100px 300px;
      grid-template-columns: 3fr 1fr;
    }
    
  • grid: <grid-template-rows> / [ auto-flow && dense? ] <grid-auto-columns>?
    问号?表示0或1,可有可无的意思。也就是dense关键字和grid-auto-columns值都可以省略。

具体说明:

  • auto-flow && dense?其实就是grid-auto-flow属性的值,等同于row或column或row dense或column dense。

    但这里row和column这两个关键字却使用了auto-flow这一个关键字代替了。那岂不有问题:什么时候解析成row,什么时候解析成column呢?

    原来,是根据auto-flow关键字是在斜杠的左侧还是右侧决定的。如果auto-flow关键字在斜杠左侧,则解析为row,如果是在右侧,则解析为column。这里的语法是在斜杠的右侧,因此,会将grid-auto-flow解析为column。

  • <grid-auto-columns>后面有个问号?,因此是可以省略的,如果省略,则将grid-auto-columns解析为auto。

我们通过几个案例学习这里的语法:

.wrapper {
    grid: repeat(2, 80px) / auto-flow 100px;
}

上面CSS代码省略了dense关键字,启用了<grid-auto-columns>,因此,等同于下面CSS:

.wrapper {
    grid-template-rows: repeat(2, 80px)
    grid-auto-flow: column;
    grid-auto-columns: 100px;
}

记住,在Grid布局中,斜杠前面都是rows相关属性,斜杠后面都是columns相关属性(下同)。

效果图:
grid

在CodePan中打开

  • grid: [ auto-flow && dense? ] <grid-auto-rows>? / <grid-template-columns>
    此语法和上面一个语法类似,只是这个斜杠前面是隐式网格,后面是显示。在这里,由于auto-flow在斜杠左侧,因此解析为row。所以:
    .wrapper {
      grid: auto-flow dense 100px / 1fr 2fr;
    }
    /*就等同于下面CSS:*/
    .wrapper {
      grid-auto-flow: row dense;
      grid-auto-rows: 100px;
      grid-template-columns: 1fr 2fr;
    }
    

四、作用在grid子项上的CSS属性

1. grid-column-start, grid-column-end, grid-row-start和grid-row-end

表示grid子项所占据的区域的起始和终止位置,包括水平方向和垂直方向。

语法如下:

.item {
    grid-column-start: <number> | <name> | span <number> | span <name> | auto
    grid-column-end: <number> | <name> | span <number> | span <name> | auto
    grid-row-start: <number> | <name> | span <number> | span <name> | auto
    grid-row-end: <number> | <name> | span <number> | span <name> | auto
}

语法中的管道分隔符|表示“或者”的意思,因此上面实际上就一个属性值,具体来讲:

  • <number>:起止与第几条网格线。
  • <name>:自定义的网格线的名称。
  • span <number>:表示当前网格会自动跨越指定的网格数量。
  • span <name>:表示当前网格会自动扩展,直到命中指定的网格线名称。
  • auto:全自动,包括定位,跨度等。

例:

<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
  <div class="box5">Five</div>
</div>
<style>
.wrapper { 
  display: grid; 
  grid-template-columns: [第一根纵线] 80px [纵线2] auto [纵线3] 100px [最后的结束线];
    grid-template-rows: [第一行开始] 25% [第一行结束] 100px [行3] auto [行末];
} 

.box1 {
  grid-column-start: 2;
  grid-column-end: 纵线3;
  grid-row-start: 第一行开始;
  grid-row-end: 3;
}

.box2 { 
  grid-column-start: 1; 
  grid-row-start: 3; 
  grid-row-end: 4; 
}

</style>

效果图:
grid

在CodePan中打开

2. grid-column和grid-row

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

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

语法上是使用斜杠分隔,如下:

.item {
    grid-column: <start-line> / <end-line> | <start-line> / span <value>;
    grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}

语法中的管道分隔符|表示“或者”的意思。

.item-b {
    grid-column: 2 / span 纵线3;
    grid-row: 第一行开始 / span 3;
}
/*等同于:*/

.item-b {
    grid-column-start: 2;
    grid-column-end: span 纵线3;
    grid-row-start: 第一行开始;
    grid-row-end: span 3;
}

3. grid-area

grid-area表示当前网格所占用的区域。在介绍grid-template-areas属性的时候就演示过该属性,我们使用grid-template-areas属性自定义一些网格区域,然后使用grid-area属性让grid子项指定使用这些区域,就自动进行了区域分布。

grid-areagrid-column/grid-row作用都是grid子项的分布,但grid-area语义要更好,识别度更佳,非常适合具有功能属性的布局区域(如头部,底部),同时,还支持非规则区域。

语法如下:

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

其中:

  • <name>:区域名称。由grid-template-areas属性创建。
  • <row-start> / <column-start> / <row-end> / <column-end>:占据网格区域的纵横起始位置。

例如:

grid-area: 2 / 2 / auto / span 3;
/*等价于*/
grid-row-start: 2;
grid-row-end: auto;
grid-column-start: 2;
grid-column-end: span 3;

效果图:
grid

在CodePan中打开

4. justify-self

justify-self表示单个网格元素的水平对齐方式。语法如下:

.item {
    justify-self: stretch | start | end | center;
}

其中(假设文档流方向没有变):

  • stretch:默认值,拉伸。表现为水平填充。
  • start:表现为网格水平尺寸收缩为内容大小,同时沿着网格线左侧对齐显示。
  • end:表现为网格水平尺寸收缩为内容大小,同时沿着网格线右侧对齐显示。
  • center:表现为网格水平尺寸收缩为内容大小,同时在当前网格区域内部水平居中对齐显示。

5. align-self

align-self指定了网格元素的垂直呈现方式,是垂直拉伸显示,还是上中下对齐,语法如下:

.item {
    align-self: stretch | start | end | center;
}

其中(假设文档流方向为网页默认):

  • stretch:默认值,拉伸。表现为垂直填充。
  • start:表现为网格垂直尺寸收缩为内容大小,同时沿着上网格线对齐显示。
  • end:表现为网格垂直尺寸收缩为内容大小,同时沿着下网格线对齐显示。
  • center:表现为网格垂直尺寸收缩为内容大小,同时在当前网格区域内部垂直居中对齐显示。

6. place-self

place-items = align-self + justify-self。(如果有兼容性顾虑,建议还是分开书写)语法如下:

.item {
    place-items: <align-self> / <justify-self>;
}

这里顺序是align-self在前,justify-self在后。

五、其他Grid知识点

  • 在Grid布局中,floatdisplay:inline-blockdisplay:table-cellvertical-align以及column-*这些属性和声明对grid子项是没有任何作用的。
  • Grid布局则适用于更大规模的布局(二维布局),而Flexbox布局最适合应用程序的组件和小规模布局(一维布局),关Flex布局请参见“写给自己看的display: flex布局教程”一文
  • 命名虽然支持中文,但由于CSS文件中文存在乱码的风险,所以……创新还是保守就看大家自己的抉择了。
  • IE10-IE15虽然名义上支持Grid布局,但支持的是老版本语法(本文是介绍的全是2.0全新语法),还需要加-ms-私有前缀。
  • 使用z-index控制层级:默认情况下回显示后来居上,但是如果设置后面的grid子项的z-index比前面的grid子项低,则前面的grid子项会遮挡后面的grid子项

参考文章:

写给自己看的display: grid布局教程

网格布局