首页 前端知识 Grid 布局:从入门到精通,一篇就够了—— 探索最强大的 CSS 布局系统

Grid 布局:从入门到精通,一篇就够了—— 探索最强大的 CSS 布局系统

2025-03-18 12:03:49 前端知识 前端哥 921 295 我要收藏

前言

 📫 大家好,我是陈三心,热爱技术和分享,欢迎大家交流,一起学习进步!

 🍅 个人主页:陈三心


背景

最近在项目中遇到了这样的一个响应式布局需求:

在不同屏幕宽度下,动态调整卡片内容的列数,并且每列的宽度不能小于 300px,同时要充分利用剩余空间。

最初,我尝试使用 Flex 布局来实现这一需求,但很快发现 Flex 虽然强大,却无法完美应对这种动态列数和固定最小宽度的场景。

正当我为此头疼时,团队中的一位伙伴提到了 CSS Grid 布局。之前对 Gird 布局仅仅局限于了解程度,并没有去深入学习,因为大部分场景使用 Flex 布局就足矣完成。既然 Flex 在该需求场景下显得有些力不从心,于是,我开始研究 Grid 的相关文档,发现其功能远比我想象的要强很多,它不仅让代码更加简洁,还提供了更强大灵活的布局控制能力。最终,通过 Grid 布局完美解决了我的问题。

实现代码其实非常简单:

.wrapper {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr) ) ;
}

上述代码中的repeat、minmax和fr是什么呢?别着急,看完本篇你将对 Grid 有一个全面的认识。

Grid 布局简介

想象一下,你在设计一个网页布局时,就像在画一张表格。你可以把网页分成很多行和列,形成一个网格系统。Grid 布局就是这样一个强大的工具,它允许你通过定义行和列来创建复杂的网页布局。你可以把内容(比如图片、文字)放到这些网格的任意位置,甚至可以跨越多行或多列。

简单来说,Grid 布局网格布局)就是将一个网页划分成一个一个的小格子,然后你可以自由地把内容放到这些格子里,或者让内容跨越多个格子。它就像是一个灵活的“网格画布”,让你可以轻松地控制网页的布局结构。

Grid 布局的优势

  1. 二维布局Grid 布局是真正的二维布局,可以同时控制行和列。相比于 Flex(主要是一维布局,只能控制行或列),Grid 布局更适合处理复杂的网页布局。

  2. 灵活控制:通过简单的 CSS 属性,可以精确控制每个网格项目的位置和大小。

  3. 代码简洁相比传统的布局方法,Grid 布局几行 CSS 就能实现复杂的布局效果,更加简洁和易于维护。

浏览器兼容性

目前,所有现代浏览器都支持 CSS Grid 布局,包括 Chrome、Firefox、Safari、Edge 等。

根据caniuse,97.21%的用户支持Grid,即 Grid 在现代浏览器中已经非常成熟,可以放心使用。

基本概念

1. 容器和项目

  • 容器:采用网格布局的区域,即为容器。

  • 项目:容器里采用网格定位的直系子元素就是“项目”。

2. 行和列

  • :容器中的水平区域,把容器分成几行。

  • :容器中的垂直区域,把容器分成几列。

3. 单元格和网格线

  • 单元格:行和列交叉形成的小格子,就是“单元格”。

  • 网格线:划分行和列的线就是“网格线”。

想象你在画一个九宫格:

  • 容器就是整个九宫格。

  • 行和列把九宫格分成 3 行 3 列(图中黄色区域)。

  • 单元格就是九宫格里的每一个小格子。

  • 网格线就是划分九宫格的横线和竖线(蓝色区域)。共有4根水平网格线和4根垂直网格线。

你可以把内容(项目)放到任意一个格子里,或者让内容跨越多行或多列。这就是 Grid 布局的核心思想!

在 Grid 布局中,容器属性项目属性是构建网格系统的核心。下面来详细介绍。

容器属性

容器属性是指定义在容器上的属性,用于定义网格的整体结构。

display 属性

display 属性用于将元素定义为网格容器,只需要将其设置为 grid 即可:

.container {
  display: grid;
}

默认情况下,Grid 的列是独占一行的,其宽度随父盒子大小。效果如下:

上述的容器元素是块级元素,但也可以设成行内元素。

  • inline-grid:生成行内网格容器。

.container {
  display: inline-grid;
}

grid-template-columns && grid-template-rows 

grid-template-columns 和 grid-template-rows 是 Grid 的核心属性,用于定义网格的列宽和行高。

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

上述代码定义了一个简单的 3x3 网格布局,左侧和右侧列宽固定,中间列宽自适应,行高均匀分布,效果如下:

fr 关键字

除了通过px、%等单位来设置网格的宽度,网格布局提供了一个新的 fr 关键字(fraction 的缩写,意为"片段"),来表示比例关系。

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

上述代码表示第一列宽度为 100px,后面两列的宽度分别为剩余宽度的 1/4 和 3/4。

你可能会有疑问?这个 fr 和百分比有啥区别?别着急,来看看下面设置了百分比的效果。

.container {
  display: grid;
  grid-template-columns: 100px 25% 75%;
}

上述例子中,我们可以发现,在设置百分比后,出现了一个滚动条。这也就是 fr 和 % 的区别:

  • fr:表示剩余空间的分配比例。
  • %:表示相对于父容器宽度的固定比例。

repeat()

有时候,重复写同样的值非常麻烦,尤其网格很多时。这时,可以使用 repeat() 函数,来简化重复定义列或行的代码

它接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。

例如,定义一个 3 列的网格,每列等宽:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr); 
}

等效于

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

auto-fill 关键字

有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用 auto-fill 关键字表示自动填充。

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

上述代码表示每列宽度300px,然后自动填充,直到容器不能放置更多的列。

等等这不就是文章开头例子的效果吗?没错,已经很接近了,只需再给每列设置最小值和最大值。

auto-fit 关键字

除了 auto-fill,还有一个关键字 auto-fit,两者的行为基本是相同的。只有当容器足够宽,可以在一行容纳所有单元格,并且单元格宽度不固定的时候,才会有差异。auto-fill 会用空格子填满剩余宽度,auto-fit 则会尽量扩大单元格的宽度。

假设容器宽度为 500px,每列最小宽度为 100px,内容只有 3 个项目:

auto-fill

[100px] [100px] [100px] [100px] [100px]

创建 5 列,其中 2 列为空白。 

auto-fit:

[166px] [166px] [166px]

创建 3 列,空白列被折叠,剩余空间均匀分配给 3 列。

minmax()

minmax() 设置每列的最小值和最大值,可以确保网格在响应式布局中既不会过小,也不会过大。

grid-template-columns: repeat(auto-fill, minmax(300px, 1fr) ) ;

上述代码(即文章开头代码)中,minmax(300px, 1fr) 表示列宽不小于300px,不大于1fr。

minmax() 搭配 repeat() 和 auto-fill,可以轻松创建动态、自适应的网格布局!

grid-row-gap &&  grid-column-gap && grid-gap

grid-row-gap 用于设置行间距,grid-column-gap 用于设置列间距。

.container {
  grid-row-gap: 10px;
  grid-column-gap: 10px;
}

Grid提供了两者的合并简写形式 grid-gap,同时定义行间距和列间距。上面代码等同于下面代码:

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

在现代浏览器中,相关属性已经进行了简化,grid- 前缀被移除,推荐使用更简洁的属性名:

  1. gap:代替 grid-gap。

  2. row-gap:代替 grid-row-gap。

  3. column-gap:代替 grid-column-gap。

到此,再来看下开头例子的完整代码:

.wrapper {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr) ) ;
}

是不是发现都已经掌握了呢。接下来让我们继续学习 Grid 布局的其它属性。

grid-auto-flow 属性

grid 容器的子元素默认会按照先行后列的顺序放置,即先填满第一行,再开始放入第二行。

这个顺序由 grid-auto-flow 属性决定,默认值是 row。也可以将它设成 column,变成先列后行。

除了常见的 row 和 column 外,还可以设置为 row dense 和 column dense。这两个值主要用于在某些项目指定位置后,剩下的项目如何自动填充空白区域。

  • row dense:按行排列,并尝试填充空白区域。

  • column dense:按列排列,并尝试填充空白区域。

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

上述会出现空白区域,而 dense 会尝试让剩余项目填充这些空白,而不是严格按顺序排列。

grid-auto-flow: row dense;

效果如下:

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

justify-items && align-items && place-items

这些属性用于控制网格项在单元格内的对齐方式。

justify-items:控制网格项在单元格内的水平对齐方式

align-items:控制网格项在单元格内的垂直对齐方式。

place-items:justify-items 和 align-items 的简写形式。

justify-items 和 align-items 这两个属性值相同,都可以取下面这些值。

.container {
  justify-items: start | end | center | stretch;
  align-items: start | end | center | stretch;
}
  • start:对齐到单元格的起始位置。

  • end:对齐到单元格的结束位置。

  • center:单元格居中对齐。

  • stretch:拉伸以占满单元格的整个宽度(默认值)。

也可使用它们的合并简写形式。 

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

1.start:对齐到单元格的起始位置

.container {
  justify-items: start;
}

2.end:对齐到单元格的结束位置

.container {
  justify-items: end;
}

3.center:单元格居中对齐。

.container {
  justify-items: center;
}

4.stretch:拉伸以占满单元格的整个宽度

.container {
  justify-items: stretch;
}

justify-content && align-content && place-content 

这些属性用于控制整个网格内容在容器内的对齐方式。

justify-content:控制网格内容在容器内的水平对齐方式。

align-content:控制网格内容在容器内的垂直对齐方式。

place-content:justify-content 和 align-content 的简写形式。

justify-content 和 align-content 这两个属性值相同,都可以取下面这些值。 

.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;  
}
  • start:对齐到容器的起始位置。。

  • end:对齐到容器的结束位置。

  • center:容器内部居中。

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

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

  • space-between:项目与项目的间隔相等,项目与容器边框之间没有间隔。

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

也可使用它们的合并简写形式。 

place-content: <align-content> <justify-content>
  • start:对齐到容器的起始位置。

  • end:对齐到容器的结束位置。

  • center:容器内部居中。

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

  • space-around:每个项目两侧的间隔相等。

  • space-between:项目与项目的间隔相等,项目与容器边框之间没有间隔。

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

grid-auto-columns && grid-auto-rows 

grid-auto-columns 和 grid-auto-rows 定义了当网格项超出显式网格范围时,浏览器自动创建的列和行的大小,即隐式网格的大小。

  • grid-auto-columns:定义隐式网格列的宽度。

  • grid-auto-rows:定义隐式网格行的高度。

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px 100px; /* 显式定义 4 列 */
  grid-template-rows: 100px 100px; /* 显式定义 2 行 */
  grid-auto-rows: 200px; /* 隐式网格行高为 200px */
  grid-gap: 10px;
}

上述代码,显示定义了4列和2行 ,但是有9个元素,就会产生隐式网格。通过 grid-auto-rows 可以指定隐式网格的行高为 200px。

grid-template-areas 属性

grid-template-areas 是 Grid 布局中用于定义网格区域的属性。它通过命名区域的方式,直观地描述网格布局的结构。

该属性一般和项目属性中的 grid-area 属性一起使用,因此会在下面详细解释。

grid-template && grid 

 grid-template 属性和 grid 属性是 Grid 布局中的简写属性,用于一次性定义网格的多个属性:

  • grid-template属性:grid-template-rows、grid-template-columns 和 grid-template-areas 这三个属性的合并简写形式。
  • grid属性:grid-template-rows、grid-template-columns、grid-template-areas、 grid-auto-rows、grid-auto-columns、grid-auto-flow 这六个属性的合并简写形式。

这种简写语法虽然方便,但会降低代码的可读性和可维护性,不推荐使用。

项目属性

项目属性是指定义在项目上的属性,用于控制每个网格项的具体位置和表现。

grid-column && grid-row

项目的位置是可以指定的,具体方法就是指定项目的四个边框,分别定位在哪根网格线。上面说过9宫格共有4根水平网格线和4根垂直网格线,通过指定这些网格线的起始和结束位置,来定义网格项占据的列和行范围。

下面这些属性用于控制项目在容器中的位置。

grid-column-start属性:网格项在列方向的起始网格线。

grid-column-end属性:网格项在列方向的结束网格线。

grid-row-start属性:网格项在行方向的起始网格线。

grid-row-end属性:网格项在行方向的结束网格线。

.item-1 {
  grid-column-start: 1; /* 从第 1 列开始 */
  grid-column-end: 3; /* 到第 3 列结束 */
  grid-row-start: 2; /* 从第 2 行开始 */
  grid-row-end: 4; /* 到第 4 行结束 */
}

上面代码中,item-1 所在的网格项目,垂直网格线是从 1 到 3,水平网格线是从 2 到 4。

命名网格线

这四个属性的值,除了指定为第几个网格线,还可以指定为网格线的名字

.item-1 {
  grid-column-start: c1;
  grid-column-end: c3;
}

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

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

上面代码指定网格布局为3行 x 3列,方括号里面依次是4根垂直网格线和4根水平网格线这八根线的名字。

span 关键字

这四个属性的值还可以使用 span 关键字,表示跨越的行数(列数),即左右边框(上下边框)之间跨越多少个网格。例如指定1号项目的左右边框跨越2个网格:

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

合并简写形式

grid-column 属性是 grid-column-start 和 grid-column-end 的合并简写形式,grid-row 属性是 grid-row-start 属性和 grid-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 {
  background: #b03532;
  grid-column: 1 / span 2;
  grid-row: 1;
}

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

justify-self && align-self && place-self 

这些属性用于设置单元格内的对齐方式。

justify-self:设置单元格内的水平对齐方式

align-self:设置单元格内垂直对齐方式。

place-self:justify-self 和 align-self 的简写形式。

justify-self 和 align-self 这两个属性值相同,都可以取下面这些值。  

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

这三个属性跟 justify-items 、align-items 和 place-items 的用法一致,区别是只作用于单个项目

grid-area 属性

grid-area 属性通常搭配项目属性 grid-template-areas 使用。

  • grid-template-areas:通过命名区域的方式,定义网格区域的布局结构。

  • grid-area:将项目分配到指定的区域。

下面这张图片,展示了我们在网站建设中最常见的布局。

 如果不使用 grid-area 的话,我们通常会这样实现:

.grid {
  display: grid;
  grid-template-columns: 120px 1fr;
  grid-template-rows: 80px 1fr;
}

.sidebar {
  grid-column: 1;
  grid-row: 2 / 3;
}

.header {
  grid-column: 2;
  grid-row: 1;
}

.content {
  grid-column: 2;
  grid-row: 2;
}

这种实现方式的可读性不够强,而 grid-template-areas 网格区域通过命名区域的方式,能够更直观地描述网格布局的结构,提高代码的可读性和可维护性。

.container {
  display: grid;
  grid-template-columns: 120px  1fr;
  grid-template-rows: 80px 1fr;
  grid-template-areas:
    ". header"
    "sidebar content";
}

.header {
  grid-area: header;
}

.sidebar {
  grid-area: sidebar;
}

.content {
  grid-area: content;
}

上面代码中,顶部是页眉区域 header,中间部分则为 siderbar 和 content。其中点(.)表示没有用到该单元格,或者该单元格不属于任何区域。

给每块网格划分区域并且命名后,我们不是给子节点分配 grid-column 和 grid-row,而是给它分配 grid-area效果: 

当希望某个特定区域跨越多行或多列时,可以在模板中重复该区域的名称。

grid-template-areas:
  "....... header  header"
  "sidebar content content";

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~

转载请注明出处或者链接地址:https://www.qianduange.cn//article/23909.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!