CSS基础之Grid布局

1,003 阅读12分钟

本文总结简化自阮一峰老师的《CSS Grid 网格布局教程》:www.ruanyifeng.com/blog/2019/0…

概述

类似这种布局

制作布局不需要复杂的CSS框架嵌套,而将网页划分成一个个网格进行布局

Grid布局与Flex布局

  • 相同:通过单个属性控制多个项目的位置
  • 不同:Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。

基本概念

容器和项目

内部采用网格布局的区域,称为“容器”,容器内被定位的子元素称为“项目”。

<div>
   <div><p>1</p></div>
   <div><p>2</p></div>
   <div><p>3</p></div>
</div>

最外层<div>就是容器,内层的三个<div>就是项目。

注意:项目只能是容器的顶层子元素,不包含项目的子元素。 比如上面代码的<p>元素就不是项目(在他上面还有<div>作为顶层子元素)。Grid 布局只对项目生效。

单元格

行和列的交叉区域,称为"单元格"(cell)。

正常情况下,n行和m列会产生n*m个单元格。比如,3行3列会产生9个单元格。

网格线

划分网格的线,称为"网格线"(grid line)。水平网格线划分,垂直网格线划分

正常情况下,n行有n+1根水平网格线,m列有m+1根垂直网格线,例如三行有四根水平网格线。

上图4X4的网格,有5根水平线,5根垂直线

容器属性

display属性

display:grid指定容器内部采用网格布局

div {
  display: grid;
}

效果如下:

默认情况下,盒子都是块级元素

但是有时候,我们想要让块级元素转化为行内元素并采用grid布局,就需要:

div {
  display: inline-grid;
}

这样就可以在一行内排布一个grid布局的块级元素了

注意:设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align等设置都将失效。

grid-template-columns 和grid-template-rows

这两个属性用于定义行高(grid-template-rows)和列高(grid-template-columns)

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

意为列宽100px,行高100px;同样,也可以使用百分比表示长度。

repeat()

防止重复录入的麻烦,简化重复值。

.container {
  display: grid;
  grid-template-columns: repeat(3, 33.33%);
  grid-template-rows: repeat(3, 33.33%);
}

repeat() 接受两个参数,第一个参数是重复的次数(上例是3),第二个参数是所要重复的值(33.33%)

同时也可以进行某种模式的重复:

grid-template-columns: repeat(2, 100px 20px 80px);

这里以这种模式重复了2次:第一列和第四列的宽度为100px,第二列和第五列为20px,第三列和第六列为80px。

auto-fill关键字

当单元格大小固定,但是容器大小不固定。希望能容纳尽量多的单元格使用auto-fill表示自动填充

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
}

意为每列列宽100px,自动填充,直到容器不能容纳更多列

fr关键字

为方便进行比例设置,如果两列的宽度分别是 1fr2fr,表示后者是前者的2倍

这里表示两列的宽度相同

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

fr可以与绝对长度的单位结合使用,这时会非常方便。

.container {
  display: grid;
  grid-template-columns: 150px 1fr 2f;
}

上面表示第一列宽度为150px,第二列宽度是第三列的一半。

minmax()

minmax()函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。

grid-template-columns: 1fr 1fr minmax(100px, 1fr);

上面代码中 ,minmax(100px, 1fr) 表示列宽不小于100px,不大于1fr。

auto关键字

auto关键字表示由浏览器自己决定长度。

grid-template-columns: 100px auto 100px;

上面代码中,第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了min-width,且这个值大于最大宽度。

为网格线命名

grid-template-columns属性和grid-template-rows属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。

.container {
  display: grid;
  grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
  grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}

这里布局为3X3,4根水平线4根垂直线,并且分别命名。

grid-row-gap,grid-column-gap 和 grid-gap 属性

grid-row-gap属性设置行与行的间隔(行间距),grid-column-gap属性设置列与列的间隔(列间距)。

.container {
  grid-row-gap: 20px;//行间距为20px
  grid-column-gap: 20px;//列间距为20px
}

上面代码中,grid-row-gap用于设置行间距,grid-column-gap用于设置列间距。

这里介绍一个简写属性:grid-gap,他是grid-row-gapgrid-column-gap的合并写法,意义是:grid-gap: <grid-row-gap> <grid-column-gap>;

因此,上面一段CSS代码等同下面:

.container {
grid-gap: 20px 20px;
}

如果grid-gap省略了第二个值,浏览器认为第二个值等于第一个值。

此外,根据最新标准,上面三个属性名的grid-前缀已经删除,grid-column-gapgrid-row-gap写成column-gaprow-gap,grid-gap写成gap

grid-template-areas 属性

在网格布局中,有“区域”(area)的定义,一个区域有单个或多个单元格组成。

grid-template-areas属性用于定义区域。

命名格式如下:

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-template-areas: 'a b c'
                       'd e f'
                       'g h i';//分号加在此处
}

意为将划分出来的9个单元格分别定名为a,b,c,d...i九个区域。

同时可以做到多个单元格合并,写法如下:

grid-template-areas: 'a a a'
                    'b b b'
                    'c c c'

即可将9个单元格分为 a、b、c 三个部分

如果某些区域不需要利用,可以使用“点”(.)表示。例如:

grid-template-areas: 'a . c'
                    '. e f'
                    'g . i'

注意:

区域的命名会影响到网格线。每个区域的起始网格线,会自动命名为区域名-start终止网格线自动命名为区域名-end

比如,区域名为header,则起始位置的水平网格线和垂直网格线叫做header-start,终止位置的水平网格线和垂直网格线叫做header-end

gird-auto-flow 属性

这个属性会决定网格的排列方法顺序。 默认放置顺序是“先行后列”(先摆满第一行再放第二行)

如图:

gird-auto-flow 属性默认值是row,可设置为 column 变成“先列后行”

如图:

当然,gird-auto-flow属性除了 rowcolumn 以外,还有row densecolumn dense两个属性值,可以用于:某些项目指定位置后,剩下项目的放置方法。

例如:下面例子中1号项目和2号项目各占据两个单元格,然后在默认的grid-auto-flow: row情况下,会产生下面这样的布局。

上图中,由于3号默认跟在2号后面,所以1号后面是空白。

现在修改为row dense,表示“先行后列尽量满”

之后效果如下:

这时,3号项目就会优先补满空白,4号项目同样补上3号上移的空白,剩下的项目按“先行后列”的顺序依次排列。

同样的情况,我们试试“先列后行尽量满”

效果如下:

这时,所有项目都会实行先列后行(竖着排),4号项目会跟在3号右边,后面的项目按序排列。

justify-items ,align-items和 place-items 属性

justify-items属性设置单元格内容的水平位置(左中右),align-items属性设置单元格内容的垂直位置(上中下)。

这两个属性都有同样的四个属性值:

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

用法如下:


.container {
  justify-items: start;
}

水平居左


.container {
  align-items: start;
}

垂直居上


内容位置也有简写方式:place-items

该属性是align-items属性和justify-items属性的合并简写形式:place-items: <align-items> <justify-items>; 若不写第二个值,则认为第二个值与第一个相同

justify-content,align-content 和place-content 属性

与上面属性类似,这三个属性作用是控制整个内容在容器内的位置(上面的属性是控制内容里,也就是单元格里的位置)。

并且这三个属性也有很多属性值:

  • start :对齐容器的起始边框
  • end:对齐容器的结束边框
  • center:容器内部居中
  • stretch :项目大小没有指定时,拉伸占据整个网格容器。
  • space-around :每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。
  • space-between:项目与项目的间隔相等,项目与容器边框之间没有间隔。
  • space-evenly:项目与项目的间隔相等,项目与容器边框之间没有间隔。

下面使用图例进行表示(仅以水平方向举例):

justify-content:start;

对齐容器的起始边框


justify-content:end;

对齐容器的结束边框


justify-content:center;

容器内部居中


justify-content:stretch;

项目大小没有指定时,拉伸占据整个网格容器。


justify-content:space-around;

每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。 。


justify-content:space-between;

项目与项目的间隔相等,项目与容器边框之间没有间隔。


justify-content:space-evenly;

项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。


同样,他的简写:place-content

place-content:<align-content> <justify-content>

如果省略第二个值,浏览器就会假定第二个值等于第一个值。

grid-auto-columns 和 grid-auto-rows 属性

有时候,一些项目的指定位置,在现有网格的外部。比如网格只有3列,但是某一个项目指定在第5行。这时,浏览器会自动生成多余的网格,以便放置项目。

grid-auto-columns属性和grid-auto-rows属性用来设置,浏览器自动创建的多余网格的列宽和行高。它们的写法与grid-template-columnsgrid-template-rows完全相同。如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。

举个栗子:

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

这里给容器内设置3X3的单元格,但是在第4行指定8号项目,第5行指定9号项目,由于设置 grid-auto-rows: 50px; 因此额外多出的两个单元格高度为50px。

项目属性

作用于单元格(项目)

grid-column-start,grid-column-end, grid-row-start 和 grid-row-end 属性。

通过指定项目的四个边框也就是网格线,就可以定位一个项目的位置。

  • grid-column-start属性:左边框所在的垂直网格线
  • grid-column-end属性:右边框所在的垂直网格线
  • grid-row-start属性:上边框所在的水平网格线
  • grid-row-end属性:下边框所在的水平网格线

举个例子: 这里仍然使用上面的3X3网格

.item-1 {
  grid-column-start: 2;
  grid-column-end: 4;
}

上述代码意为:1号项目左边框( grid-column-start)在第2根垂直网格线,右边框( grid-column-end)在第4根垂直网格线。

代码中未定义上下边框,默认:上边框是第一根水平网格线,下边框是第二根水平网格线。

现在我们指定四个边框:

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

此外,定位的四个属性还可以用span关键字,表示“跨越”,即左右边框/上下边框跨越多少个网格。

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

上述代码意为跨越2个。 效果:

.item-1 {
  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;

/* 等同于 */

.item-1 {
  grid-column: 1 / span 2;
  grid-row: 1 / span 2;
}

简写过程中需要用 “/” 分开两数值(网格线名)

同样,也可省略“end结束”数值

.item-1 {
  grid-column: 1;
  grid-row: 1;
}

grid-area 属性

用于指定项目放在哪个区域

.item-1 {
  grid-area: e;
}

让项目1定位于e区域

这个属性还可以通过直接输入开始和结束的网格线来定位。

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

上面的项目1可表示为:


.item-1 {
  grid-area: 2 / 2 / 3 / 3;
}

上下对比着看,分别为顺时针的:“上左下右”

justify-self ,align-self 和 place-self 属性

justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。

align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目。

同样具有四个值:

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

举个栗子:

.item-1  {
  justify-self: start;
}

他的简写:place-self: <align-self> <justify-self>;

例如:place-self: center center;

如果省略第二个值,place-self属性会认为这两个值相等。