树欲静而风不止
叙述前端的戎码生涯

Grid布局-实例篇

一、概述

目前,CSS 网格布局(Grid)是当之无愧的最强 CSS 布局方案。

它的核心能力是将网页拆解为整齐的网格,只要灵活组合这些网格,就能轻松实现各种复杂布局。要知道,这类布局在以前,必须借助复杂的 CSS 框架才能做到,而现在浏览器已经原生支持了。

图片

如上图所示的布局,恰好是 Grid 布局的专长领域。Grid 布局与 Flex 布局存在共通之处:二者均具备对容器内多个项目位置的精准控制能力。但其本质区别在于:Flex 布局以轴线为核心机制,仅支持沿主轴或交叉轴对项目进行定位,属于一维布局模式;而 Grid 布局的实现逻辑是先将容器分割为清晰的 “行” 与 “列”,形成独立的单元格结构,再通过指定项目所属单元格完成定位,属于二维布局模式。就布局能力而言,Grid 布局在灵活性与功能性上均远优于 Flex 布局。

二、基本概念

2.1 容器和项目

当一个区域采用网格布局时,该区域可称为 “容器”(container);而容器内部那些以网格方式定位的直接子元素,被称作 “项目”(item)。

<div>  
<span><p>1</p></span>
<span><p>2</p></span>
</div>

来看这段代码:最外层的<div>是容器,里面的两个<span>是项目。这里要特别注意一个规则:项目只能是容器的直接子元素,项目自己的子元素(像代码里的<p>)不算项目。而且,Grid 布局只对项目生效,对其他元素不产生影响

三、容器属性

我们可以把 Grid 布局的属性分成两类:一类是加在容器上的,叫做容器属性;另一类是加在项目上的,叫做项目属性。这一节,我们先从容器属性开始学习。

3.1 display 属性

当我们为容器定义 display: grid 时,该容器便会启用网格布局模式。

div {
display: grid;
}
图片

上图为display: grid的布局效果。

需要注意的是,容器默认是块级元素,但这并非固定不变,我们也能根据布局需求,把它设置成行内元素。

div {
display: inline-grid;
}

大家可以看到,上面这段代码做了两件事:一是把这个<div>设为行内元素,二是让这个元素的内部使用网格布局。

图片

上图为display: inline-grid的布局效果。

这里有个关键知识点必须记住:当容器采用网格布局后,项目上之前设置的一些样式会失效。
比如控制浮动的 float,控制显示方式的
display: inline-block 和 display: table-cell,
控制垂直对齐的 vertical-align,还有用于多列布局的
column-* 相关属性,全都不再起作用。

3.2、grid-template-columns 属性,grid-template-rows 属性

记住这个关键步骤:容器设置好网格布局后,就要开始划分行和列了。我们用 grid-template-columns 属性来规定每一列有多宽,用 grid-template-rows 属性来规定每一行有多高,这两个属性是构建网格结构的基础。

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

上述代码中,网格布局被配置为三行三列的结构,其列宽属性(grid-template-columns)与行高属性(grid-template-rows)的取值均为 100px,即网格的列宽与行高统一为 100px。

图片

网格布局中,行列尺寸的定义支持多种单位类型。除绝对单位外,百分比单位也是常用的尺寸定义方式之一。

.container {
display: grid;
  grid-template-columns: 33.33% 33.33% 33.33%;
  grid-template-rows: 33.33% 33.33% 33.33%;
}

(1)repeat()

当行列尺寸存在大量重复值时,直接重复书写会降低代码效率。在此情况下,可通过 repeat() 函数对重复值进行简化定义。上述代码基于 repeat() 函数的改写结果如下。

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

repeat() 函数的参数构成明确:第一个参数用于设定重复的次数(如示例中的 3),第二个参数用于指定需重复的目标值。

需要注意的是,repeat() 函数不只能重复单个值,就算是一种组合模式,它也能照样重复。比如像 “宽 20px + 宽 30px” 这样的模式,也可以用 repeat() 来重复。

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

大家看这段代码,它定义了 6 列,每列的宽度对应关系很清晰:

  • 第 1 列和第 4 列:100px
  • 第 2 列和第 5 列:20px
  • 第 3 列和第 6 列:80px这种分布其实是 “100px 20px 80px” 模式重复了 2 次的结果。
图片

(2)auto-fill 关键字

大家可以想象这样一种情况:单元格大小是固定的,但容器有多大我们不确定。这时候如果想让每行(或每列)能塞下多少单元格就塞多少,怎么办呢?用 auto-fill 关键字就可以了,它能自动帮我们填充最多的单元格。

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

上述代码中,列宽参数被设定为 100px,配合自动填充逻辑,会使网格在容器空间内持续填充 100px 宽的列,直至容器剩余空间小于单列宽度(100px)时停止。

图片

auto-fitauto-fill 功能相近,核心行为一致。差异仅出现于以下场景:容器宽度足以容纳全部单元格,且单元格宽度为非固定值。此时,auto-fill 的表现为以空白单元格填充剩余空间;auto-fit 的表现为通过扩展单元格宽度消耗剩余空间。

(3)fr 关键字

fr 关键字(源自 “fraction”,意为 “片段”)是网格布局中用于表达比例关系的专用单位。例如,当两列的宽度属性分别为 1fr2fr 时,二者的宽度比例为 1:2,即后者的宽度为前者的两倍。

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

上述代码中,网格的列数为 2,且两列的宽度属性被配置为等值,即两列宽度相同。

图片

fr 单位支持与绝对长度单位联合使用,这种混合模式可高效处理 “固定尺寸 + 比例分配” 的布局场景,显著提升配置便捷性。

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

上述代码中,列宽配置为:第一列宽度值为 150px(绝对长度),第二列与第三列的宽度比例为 1:2(即第二列宽度为第三列的 1/2)。

图片

(4)minmax()

可以把 minmax() 函数理解为 “设定长度的上下限”。它需要两个值:一个是最小值,一个是最大值。比如 minmax(100px, 200px) 就表示长度不能小于 100px,也不能大于 200px,会在这个范围内根据情况调整。

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

大家可以这样理解这段代码里的 minmax(100px, 1fr):这列的宽度有两个限制 —— 最小不能小于 100px,最大不能超过 1fr。也就是说,不管容器怎么变,这列再窄不会窄于 100px,也不会宽过 1fr 所分配的空间。

(5)auto 关键字

auto 作为网格布局中的长度关键字,其作用是将长度的计算权交由浏览器,由浏览器根据上下文(如内容大小、容器空间等)自动决定最终长度。

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

上述代码中,第二列的宽度计算规则为:默认等于该列所有单元格的最大宽度;当单元格内容的 min-width 属性值存在且大于上述最大宽度时,列宽将被 min-width 值覆盖。

(6)布局实例

grid-template-columns 是网页布局的高效工具,对于两栏式布局,通过单行代码即可快速实现(例如 grid-template-columns: 200px 1fr;)。

.wrapper {
display: grid;
  grid-template-columns: 70% 30%;
}

在上述代码示例里,通过 grid-template-columns 属性将两栏布局的宽度比例配置为 70% 与 30%,即左栏占 70%,右栏占 30%。

对于传统的十二网格布局,通过 grid-template-columns 等属性可简化实现过程,例如使用 repeat(12, 1fr) 即可快速定义 12 列等宽网格,编写起来十分便捷。

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

3.3、grid-row-gap 属性,grid-column-gap 属性,grid-gap 属性

grid-row-gap 属性的作用是指定网格布局中行与行的间隔距离(行间距),grid-column-gap 属性的作用是指定列与列的间隔距离(列间距),二者共同控制网格内部的间距分布。

.container {
grid-row-gap: 20px;
  grid-column-gap: 20px;
}
图片

为了简化代码,我们可以用 grid-gap 同时设置列间距和行间距,它是 grid-column-gapgrid-row-gap 的简写形式。具体怎么写呢?语法如下:

grid-gap: <grid-row-gap> <grid-column-gap>;
.container {
grid-gap: 20px 20px;
}

grid-gap 的简写语法中,当仅传入一个值时,浏览器会将该值同时应用于 grid-row-gapgrid-column-gap,即第二个值默认与第一个值相同。

最新标准对网格间距属性名称进行了简化,具体调整如下:

  • grid-column-gap → 现 column-gap
  • grid-row-gap → 现 row-gap
  • grid-gap → 现 gap即三个属性均已移除 grid- 前缀。

3.4 grid-auto-flow 属性

网格布局划分完成后,容器的子元素将按照预设的默认顺序自动填充至网格单元。默认填充顺序为 “先行后列”,即优先填充当前行的所有列,待该行填充完毕后,再启动下一行的填充流程,其排列顺序与下图中数字标识的顺序相符。

图片

grid-auto-flow 属性定义了网格子元素的自动布局顺序:其初始值为 row,表示采用 “先行后列” 的排列逻辑(沿行方向优先填充);当属性值设为 column 时,排列逻辑切换为 “先列后行”(沿列方向优先填充)。

grid-auto-flow: column;

在上述代码中,当 grid-auto-flow 被设置为 column 时,网格子元素的自动排列顺序切换为 “先列后行”,具体顺序如以下图示。

图片

grid-auto-flow 的可选值还包括 row densecolumn dense。它们的核心功能是在布局中存在指定位置的项目时,优化剩余项目的自动放置逻辑 —— 通过 “紧凑填充” 的方式减少空白区域,使布局更密集。

在以下示例中,1 号与 2 号项目均被设置为占据两个单元格;由于 grid-auto-flow 默认为 row(先行后列),剩余项目将按此规则填充,最终布局效果如下。

图片

图中 1 号项目后的空位源于默认布局逻辑:3 号项目会接续 2 号项目的位置排列。当grid-auto-flow设为row dense时,布局规则调整为 “先行后列” 且启用密集填充模式,剩余项目将优先填补空白区域,尽可能避免空格。

grid-auto-flow: row dense;

上面代码的效果如下。

图片

上图会先填满第一行,再填满第二行,所以3号项目就会紧跟在1号项目的后面。8号项目和9号项目就会排到第四行。

如果将设置改为column dense,表示”先列后行”,并且尽量填满空格。

grid-auto-flow: column dense;
图片

上图呈现的是 “先列后行” 的填充逻辑,布局时会优先填满一列再推进至下一列。基于此规则,3 号项目落入第一列,4 号项目进入第二列,受前面项目排列影响,8 号与 9 号项目被挤压到第四列。

3.5、justify-items 属性,align-items 属性,place-items 属性

justify-itemsalign-items 是网格布局中控制单元格内容对齐的核心属性:前者针对水平方向,定义内容在单元格内的左右位置(如左对齐、居中、右对齐);后者针对垂直方向,定义内容在单元格内的上下位置(如顶部对齐、居中、底部对齐)。

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

justify-itemsalign-items 具有一致的语法结构,二者可使用的属性值完全相同,具体取值如下。

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

上述代码设置单元格内容为左对齐,对应的效果如下图所示。

图片
.container {
align-items: start;
}

上述代码设置单元格内容为头部对齐,对应的效果如下图所示。

图片

place-items 属性用于合并声明 align-itemsjustify-items,是二者的简写形式,可一次性配置单元格内容的垂直对齐与水平对齐规则。

place-items: <align-items> <justify-items>;
place-items: start end;

place-items 的简写语法中,当仅指定一个值时,浏览器会将该值同时应用于 align-itemsjustify-items,即省略的第二个值默认与第一个值一致。

3.6、justify-content 属性,align-content 属性,place-content 属性

对于网格布局的容器而言,justify-content 控制的是整个内容区域在容器中的水平对齐位置(左、中、右),align-content 控制的是同一内容区域在容器中的垂直对齐位置(上、中、下)。

关键区别:与 justify-items/align-items 的对比

二者极易与控制单元格内容对齐的属性混淆,核心差异如下:

属性作用对象生效条件控制方向
justify-content整个网格内容区域网格总宽度 < 容器宽度水平方向(左 / 中 / 右)
align-content整个网格内容区域网格总高度 < 容器高度垂直方向(上 / 中 / 下)
justify-items单个单元格内的内容单元格宽度 > 内容宽度水平方向
align-items单个单元格内的内容单元格高度 > 内容高度垂直方向
.container {
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}

justify-contentalign-content 不仅功能逻辑对应(分别控制水平 / 垂直对齐),语法规则与可取值也完全相同,具体取值如下。需注意,下方示例图以 justify-content 为演示对象,align-content 的效果图示仅方向不同 —— 将水平对齐效果转换为垂直对齐即可

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

place-content 作为网格容器级对齐的简写属性,整合了 align-content(控制内容区域垂直位置)和 justify-content(控制内容区域水平位置)的功能,通过单条声明即可同时定义两者的属性值。

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

place-content 的简写规则中,若省略第二个参数,用户代理(浏览器)将默认第二个参数的值等于第一个参数的值,即内容区域的垂直对齐方式与水平对齐方式取相同值。

3.7、grid-auto-columns 属性,grid-auto-rows 属性

grid-auto-columns 属性的功能是指定浏览器自动创建的额外列网格的宽度,grid-auto-rows 属性的功能是指定自动创建的额外行网格的高度。二者与 grid-template-columnsgrid-template-rows 具有完全一致的语法结构;若未对其进行声明,用户代理(浏览器)将根据对应网格内单元格内容的尺寸,确定新增网格的列宽和行高。

在以下示例里,通过网格属性将容器划分为 3 行 ×3 列的显式网格。然而,布局中 8 号项目的位置被指定为第 4 行,9 号项目的位置被指定为第 5 行,超出了预设的网格行数。

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

上述代码中,显式定义的原始网格行高为 100px,同时通过配置指定,浏览器自动创建的新增行网格高度统一为 50px,实现了原始行与新增行的高度差异化设置。

图片

3.8、grid-template 属性,grid 属性

grid-template 属性为合并声明属性,其涵盖范围包括 grid-template-columnsgrid-template-rowsgrid-template-areasgrid 属性作为更为全面的合并简写属性,涵盖 grid-template-rowsgrid-template-columnsgrid-template-areasgrid-auto-rowsgrid-auto-columnsgrid-auto-flow 六项属性。基于前述基础属性已完成讲解,此处不对这两个简写属性进行详细阐述。

四、项目属性

4.1、grid-column-start 属性,grid-column-end 属性,grid-row-start 属性,grid-row-end 属性

指定网格项目位置的核心方法,是为项目的四个边框(上、下、左、右)分别设定对应的网格线,通过边框与网格线的绑定关系,精准确定项目在网格中的位置。

  • grid-column-start属性:左边框所在的垂直网格线
  • grid-column-end属性:右边框所在的垂直网格线
  • grid-row-start属性:上边框所在的水平网格线
  • grid-row-end属性:下边框所在的水平网格线
.item-1 {
grid-column-start: 2;
  grid-column-end: 4;
}

这段代码对 1 号项目的水平位置做了限定:左边框对齐第二根垂直网格线,右边框对齐第四根垂直网格线,这意味着项目会横跨这两根网格线之间的区域。

图片

图示中,1 号项目的水平方向边框(左右)已明确指定网格线,垂直方向边框(上下)未做声明。依据默认布局规则,其垂直方向边框将采用初始定位:上边界与第一根水平网格线重合,下边界与第二根水平网格线重合。

1 号项目为手动定位,其余项目依赖浏览器自动布局,其排列顺序由grid-auto-flow属性控制:默认row对应 “先行后列”。若要探索不同布局效果,可将属性值分别改为column(先列后行)、row dense(行方向消除空位)、column dense(列方向消除空位),对比其他项目的位置差异。

下面代码针对1号项目指定四个边框线效果。

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

大家可以这样理解:这四个控制边框的属性,除了直接写网格线编号,还能用span加数字,意思是 “跨几个格子”。比如想让项目左右边框之间跨 2 个网格,就可以写span 2;上下边框之间跨 3 个网格,也用span 3,这样就不用算具体是哪根网格线了。

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

这段代码通过相关属性(如grid-column: span 2)明确,1 号项目的左边框与右边框之间横向跨越 2 个网格,对应水平方向占据 2 个网格的空间。

图片

这与下面的代码效果完全一样。

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

若通过这四个属性定位项目时出现重叠现象,解决显示顺序的方案是使用z-index属性:为重叠项目分别设置不同的z-index值,值较高的项目将覆盖值较低的项目,以此控制重叠时的可见层级。

4.2、grid-column 属性,grid-row 属性

grid-columngrid-column-startgrid-column-end 的简写,格式通常为 起始线 / 结束线(如 2 / 4);grid-rowgrid-row-startgrid-row-end 的简写,格式一致,通过单条声明即可完成项目水平或垂直方向的定位。

.item {
grid-column: <start-line> / <end-line>;
  grid-row: <start-line> / <end-line>;
}
.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 的行位置被限定在第一行,列方向上通过网格线定位 —— 左侧对齐第一根垂直列线,右侧对齐第三根垂直列线,即横向跨越从第 1 列到第 2 列的区域。

grid-columngrid-row中使用span关键字的示例:grid-column: 2 / span 3表示从第 2 根列线开始向右跨 3 个网格;grid-row: span 2表示从当前行线开始向下跨 2 个网格,简化了定位写法。

.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;
}

在上述代码里,项目 item-1 的布局范围明确:行方向覆盖第一行和第二行,列方向覆盖第一列和第二列,整体占据一个 2 行 2 列的网格区域。

图片

若省略斜杠及后面的部分,默认表示跨越一个网格。

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

上述代码中,项目 item-1 位于左上角的第一个网格。

4.3、justify-self 属性,align-self 属性,place-self 属性

justify-self 属性用于指定单个网格项目的内容在其单元格内的水平对齐方式(左、中、右),其语法规则与 justify-items 完全一致,但应用范围限定为单个项目;align-self 属性用于指定单个网格项目的内容在其单元格内的垂直对齐方式(上、中、下),其语法规则与 align-items 完全一致,应用范围同样限定为单个项目。

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

justify-selfalign-self 均可取以下四个值:

  • start:对齐单元格的起始边缘;
  • end:对齐单元格的结束边缘;
  • center:在单元格内部居中;
  • stretch:拉伸并占满单元格的整个宽度(默认值)。
.item-1  {
justify-self: start;
}
图片

place-self 的语法通常为 “垂直值 水平值”(如 place-self: center end 对应 align-self: center; justify-self: end),若只写一个值,则同时应用于垂直和水平方向,简化了单个项目的对齐设置。

place-self: <align-self> <justify-self>;
place-self: center center;

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

至此,Grid 布局的常用属性已基本介绍完毕。掌握这些内容,足以应对工作中的大部分布局需求。

作为当前主流的布局方案,Grid 与 Flex 布局在众多前端框架(如 Bootstrap、Tailwind CSS、Element UI)中均有广泛且重要的应用。因此,对于 Web 开发人员而言,熟练掌握二者是十分必要的。

此外,传统布局方式(通过 display、position、float 组合实现)虽操作相对繁琐,但它是所有 CSS 布局的基础,同样需要扎实掌握,不可忽视。

虽然Grid属性较多但是只要掌握常用的几个足以慢慢上手

在文章的最后,我会给出开篇第一张图(即文章封面图)的布局代码作为示例,如下所示:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
      <title>戎码生涯-Grid布局</title>
      <style >
      .container {
          display: grid;
              grid-template-columns: repeat(3, 100px);
              grid-auto-rows: 40px;
              gap: 5px;        
      }
      .container>span:nth-child(1) {
          grid-column-start: span 2;
              grid-row-start: span 2;
          }
          .container>span:nth-child(3) {
          grid-row-start: span 2;
          }
          .container>span {
          display: grid;
              place-items: center;
              border-radius: 10px;
              background: rgb(195, 93, 199);
          }    
      </style>
</head>
<body>
  <span class="container">
      <span>1</span>
          <span>2</span>
          <span>3</span>
          <span>4</span>
          <span>5</span>
      </span>
</body>
</html>

赞(1)
未经允许不得转载:OveUI » Grid布局-实例篇
分享到