百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

详解CSS Grid布局

myzbx 2025-02-26 13:01 27 浏览

本文译自A Complete Guide to CSS Grid(
https://css-tricks.com/snippets/css/complete-guide-grid/#grid-animation)

CSS Grid 布局简介

CSS Grid是一种二维的布局方式,和以前的布局方式完全不同,CSS常用来给页面布局,但做的总不够好,以前我们用table布局,后来用float、position、inline-block,这些方式本质上都是hack,缺少一些重要的特性(比如垂直居中),flex布局是一个很好的布局方式,但它基于轴的布局方式在其他方面用处更大,并且可以和Grid布局很好的配合使用,Grid布局是专门用来解决我们一直以来布局页面时所碰到的各种问题的。

本指南围绕Grid布局的最新特性讲解,所以不会考虑老旧的浏览器兼容性。

CSS Grid基础

到2017年3月,大部分浏览器都支持Grid布局(无需前缀):Chrome(包括Android)、Firefox、Safari(包括IOS)、Opera。IE10和IE11也能通过一定的途径支持,所以现在是时候使用Grid布局了。

首先你需要一个父元素,并设置dispaly: grid,通过grid-template-columnsgrid-template-rows设置列和行的大小,然后向父元素中添加子元素,并设置grid-columngrid-row属性,和flex布局类似,子元素的原始顺序并不重要,CSS可以任意控制它们的顺序,这使得通过媒体查询排列元素变得超级简单。想象下你把整个页面设置成grid布局,然后对不同的屏幕宽度自适应时完全重新排列,只需要几行CSS。Grid是有史以来引入的最强大的CSS模块之一。

重要的CSS Grid术语

在深入学习Grid布局之前,先了解一些重要的术语,它们有些相似,如果不先了解,后面就比较容易混淆,不过不用担心,这些概念并不多。

Grid Container

应用display: grid的元素,是所有grid items的直接父级。下面的例子中,container就是grid container。

Grid Item

Grid Container的子元素,下面的例子中,item元素就是grid item,但sub-item不是。

Grid Line

Grid Line是用来构成网格布局的分隔线。它们可以是垂直的(“列网格线”)或水平的(“行网格线”),位于行或列的任意一侧。这里的黄线是列网格线的一个例子。

Grid Cell

Grid Cell是相邻两行和相邻两列之间的区域,称为网格单元,下图黄色部分是行网格线1和2,列网格线2和3之间的网格单元。

Grid Track

Grid Track是相邻网格线之间的区域,你可以理解成一行或一列网格。下图黄色部分是第2和第3行网格线之间的Grid Track

Grid Area

Grid Area是由4条网格线围起来的区域。一个Grid Area可以由若干个网格单元组成,下图黄色部分的是行网格线1和3,列网格线1和3围起来的Grid Area

CSS Grid属性

CSS Grid属性分为2类,分别是用在父元素和子元素上的。

用在父元素Grid Container上的属性

  • display
  • grid-template-columns
  • grid-template-rows
  • grid-template-areas
  • grid-template
  • grid-column-gap
  • grid-row-gap
  • grid-gap
  • justify-items
  • align-items
  • place-items
  • justify-content
  • align-content
  • place-content
  • grid-auto-columns
  • grid-auto-rows
  • grid-auto-flow
  • grid

1、display

.container {
  display: grid | inline-grid;
}

可取值:

  • grid——生成块级grid
  • inline-grid——生成行内grid

2、grid-template-columns、grid-template-rows
用一行空格分开的值来定义网格的行和列,这些值代表
Grid Track的大小,空格代表分隔线Grid Line

  • track-size —— 可以是一个长度、百分比、或者fr单位的值
  • line-name —— 你对网格线的命名
.container {
  grid-template-columns: ...  ...;
  /* e.g.
      1fr 1fr
      minmax(10px, 1fr) 3fr
      repeat(5, 1fr)
      50px auto 100px 1fr
  */
  grid-template-rows: ... ...;
  /* e.g.
      min-content 1fr min-content
      100px 1fr max-content
  */
}

网格线自动取正值,-1是最后一行的备选值。

但是你也可以直接给网格线命名,注意名称时的括号语法:

.container {
  grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
  grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}

需要注意的是分隔线可以有多个名字。比如下面第二条线有2个名字:row1-endrow2-start

.container {
  grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}

如果需要定义重复的部分,可以用repeat()来简化:

.container {
  grid-template-columns: repeat(3, 20px [col-start]);
}

上面的写法和下面的等价:

.container {
  grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
}

如果多条分割线使用同样的名字,则可以通过名字加计数来区分。

.item {
  grid-column-start: col-start 2;
}

fr单位可以把父元素空闲部分按比例划分给Grid Track。比如下面的写法会把Grid Track设为父元素宽度的三分之一。

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

空闲部分是非自适应元素计算完毕后剩下的空间。比如下面的例子中,对fr可用的空间不包括50px:

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

3、grid-template-areas
grid-template-areas用名字定义网格区域,重复网格名字使该区域包括覆盖的网格单元,句号代表空网格单元。语法本身让网格结构十分明了。

可取值:

  • grid-template-areas —— 网格区域名字
  • . —— 空的网格单元
  • none —— 未定义网格区域
.container {
  grid-template-areas:
    " | . | none | ..."
    "...";
}

举个例子:

.item-a {
  grid-area: header;
}
.item-b {
  grid-area: main;
}
.item-c {
  grid-area: sidebar;
}
.item-d {
  grid-area: footer;
}

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
  grid-template-rows: auto;
  grid-template-areas:
    "header header header header"
    "main main . sidebar"
    "footer footer footer footer";
}

上面的代码会创建一个3行4列的网格区域,第一行是header区域,中间的一行由2块main区域、1块空单元和1块sidebar区域组成,最后一行是footer区域。

每一行的网格单元数量要相同。可以用任意数量的紧挨着的句号来声明一个空单元格。只要句号之间没有空格,它们就代表一个空单元格。

需要注意的是,grid-template-areas命名的是区域,当使用该属性时,区域两端的线会被自动命名。如果网格区域被命名成foo,该区域的第1行和第1列分隔线都会自动名称成foo-start,最后1行和最后1列的分隔线被命名成foo-end,这也意味着一些分隔线会有多个名字,比如上面的例子中,有一条分隔线有3个名字:header-startmain-start, 和 footer-start

4、grid-template
grid-template可以把grid-template-rowsgrid-template-columnsgrid-template-areas简写到一起。

可取值:

  • none —— 3个属性都设为默认值。
  • / —— 分别设置grid-template-rowsgrid-template-columns的值,并把grid-template-areas设为none。
.container {
  grid-template: none |  / ;
}

它的值还可以更复杂,但使用起来更方便:

.container {
  grid-template:
    [row1-start] "header header header" 25px [row1-end]
    [row2-start] "footer footer footer" 25px [row2-end]
    / auto 50px auto;
}

上面的写法和下面的等价:

.container {
  grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end];
  grid-template-columns: auto 50px auto;
  grid-template-areas:
    "header header header"
    "footer footer footer";
}

由于grid-template不会重置隐式网格属性(grid-auto-columnsgrid-auto-rowsgrid-auto-flow),这可能是您在大多数情况下想要做的,因此建议使用grid属性而不是grid-template

5、column-gap、row-gap、grid-column-gap、grid-row-gap
定义分隔线的粗细。可以理解成设置行或列的间距。

  • —— 长度值
.container {
  /* 新写法 */
  column-gap: ;
  row-gap: ;

  /* 旧写法 */
  grid-column-gap: ;
  grid-row-gap: ;
}

举个例子:

.container {
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;
  column-gap: 10px;
  row-gap: 15px;
}

间距只在行或列中间存在,边缘部分不存在。

需要注意的是,grid前缀会被移除,grid-column-gapgrid-row-gap 会被重命名成 column-gaprow-gap,无前缀的语法已经被Chrome 68+, Safari 11.2 Release 50+, and Opera 54+支持。

6、gap、grid-gap
row-gapcolumn-gap的简写形式。

可取值:

  • —— 长度值
.container {
  /* 新写法 */
  gap:  ;

  /* 旧写法 */
  grid-gap:  ;
}

举个例子:

.container {
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;
  gap: 15px 10px;
}

如果没有定义row-gap的值,它会自动等于column-gap

7、justify-items
grid items的水平对齐方式,适用container中所有的grid items

可取值:

  • start —— 向单元格的起始边对齐。
  • end —— 向单元格的尾部对齐。
  • center —— 单元格内居中。
  • stretch —— 宽度填满单元格(这是默认值)。
.container {
  justify-items: start | end | center | stretch;
}

举个例子:

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

该对齐方式也可以用justify-self单独给grid items设置。

8、align-items
grid items的垂直对齐方式,值和用法和justify-items一样。该对齐方式也可以用align-self单独给grid items设置。

9、place-items
align-itemsjustify-items的简写方式。

可取值:

  • / —— 第1格值代表align-items,第2个值代表justify-items,如果第2个值省略了,第1个值会默认代表这2个属性。
.center {
  display: grid;
  place-items: center;
}

10、justify-content
有时整体网格的大小比容器小,比如所有的网格都是用px指定了大小,这时可以设置网格在容器中的对齐方式,
justify-content设置网格的水平对齐方式。

可取值:

  • start —— 向容器的头部对齐。
  • end —— 向容器的尾部对齐。
  • center —— 在容器中水平居中。
  • stretch —— 重新适配items的大小把容器的宽度填满。
  • space-around —— 使每个网格的列间距相等,两边的留白是列间距的一半。
  • space-between —— 使每个网格的列间距相等,两边不留白。
  • space-evenly —— 使每个网格的列间距相等,两边的留白等于列间距。
.container {
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
}

举个例子:

.container {
  justify-content: start;
}
.container {
  justify-content: end;
}
.container {
  justify-content: center;
}
.container {
  justify-content: stretch;
}
.container {
  justify-content: space-around;
}
.container {
  justify-content: space-between;
}
.container {
  justify-content: space-evenly;
}

11、align-content
值和用法和
justify-content一样,区别是align-content用来设置垂直方向的对齐方式。

12、place-content
justify-contentalign-content的简写方式。

可取值:

  • /

13、grid-auto-columns、grid-auto-rows
指定任何自动生成的
grid tracks的大小。

用法:

.container {
  grid-auto-columns:  ...;
  grid-auto-rows:  ...;
}

举个例子,来看看隐式grid tracks是怎么创建的。

.container {
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px;
}

上面的代码创建了一个2x2的网格。
接下来用
grid-columngrid-row设置item的位置:

.item-a {
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b {
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}

这时item-b就超出了2x2的网格范围,超出部分会默认创建隐式的grid tracks,但是这些隐式的grid tracks的宽度是0,这时我们就可以通过grid-auto-columnsgrid-auto-rows为它们设置宽度:

.container {
  grid-auto-columns: 60px;
}

14、grid-auto-flow
grid-auto-flow控制item的自动排列方式。

可取值:

  • row —— 按顺序填充每一行,必要时新增行。
  • column —— 按顺序填充每一列,必要时新增列。
  • dense —— 较小的item排在前面。
.container {
  grid-auto-flow: row | column | row dense | column dense;
}

注意dense只是虚拟的改变items的顺序,这可能导致顺序混乱。

举个例子:

item-a
item-b
item-c
item-d
item-e

接着你定义了一个2x5的网格,并把grid-auto-flow设为row(row也是默认值):

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: row;
}

在给item定位的时候,你只设置了2个:

.item-a {
  grid-column: 1;
  grid-row: 1 / 3;
}
.item-e {
  grid-column: 5;
  grid-row: 1 / 3;
}

这时我们的网格看起来就是这样的:

如果我们把grid-auto-flow设为column,item-bitem-citem-d 就会按顺序沿着列来排:

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: column;
}

15、grid
可以把
grid-template-rowsgrid-template-columnsgrid-template-areasgrid-auto-rowsgrid-auto-columns, 和 grid-auto-flow 写到一起。

可取值:

  • none —— 所有属性设为默认值。
  • —— 跟 grid-template 一样。
  • / [ auto-flow && dense? ] ?
  • [ auto-flow && dense? ] ? /

比如下面两种写法等价( / ):

.container {
  grid: 100px 300px / 3fr 1fr;
}

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

下面的两种写法等价(auto-flow / ):

.container {
  grid: auto-flow / 200px 1fr;
}

.container {
  grid-auto-flow: row;
  grid-template-columns: 200px 1fr;
}

下面的两种写法等价(auto-flow dense / ):

.container {
  grid: auto-flow dense 100px / 1fr 2fr;
}

.container {
  grid-auto-flow: row dense;
  grid-auto-rows: 100px;
  grid-template-columns: 1fr 2fr;
}

下面的两种写法等价( / auto-flow ):

.container {
  grid: 100px 300px / auto-flow 200px;
}

.container {
  grid-template-rows: 100px 300px;
  grid-auto-flow: column;
  grid-auto-columns: 200px;
}

还有更复杂但更简洁的写法,下面的两种写法等价:

.container {
  grid: [row1-start] "header header header" 1fr [row1-end]
        [row2-start] "footer footer footer" 25px [row2-end]
        / auto 50px auto;
}

.container {
  grid-template-areas:
    "header header header"
    "footer footer footer";
  grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
  grid-template-columns: auto 50px auto;
}

用在子元素Grid Item上的属性

  • grid-column-start
  • grid-column-end
  • grid-row-start
  • grid-row-end
  • grid-column
  • grid-row
  • grid-area
  • justify-self
  • align-self
  • place-self

1、grid-column-start、grid-column-end、grid-row-start、grid-row-end
通过指定分隔线的方式定义网格单元在网格中的位置,
grid-column-start/grid-row-start是网格单元开始的地方,grid-column-end/grid-row-end是结束的地方。

可取值:

  • —— 代表分隔线的数字或者名字。
  • span —— 包括指定数量的网格单元。
  • span —— 包括单元格直到碰到指定名字的分隔线。
  • auto —— 自动放置,默认1个单元格。

举个例子:

.item-a {
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start;
  grid-row-end: 3;
}
.item-b {
  grid-column-start: 1;
  grid-column-end: span col4-start;
  grid-row-start: 2;
  grid-row-end: span 2;
}

如果没有指定grid-column-end/grid-row-end,item默认包含1个单元。

item还能彼此覆盖,可以用z-index控制层级。

2、grid-column、grid-row
grid-column-startgrid-column-endgrid-row-startgrid-row-end的简写形式。

可取值:

  • / —— 写法和非简写值一样。
.item {
  grid-column:  /  |  / span ;
  grid-row:  /  |  / span ;
}

举个例子:

.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}

3、grid-area
grid-area给item命名,这样使用grid-template-areas可以直接引用item的名字。并且此属性还可以作为 grid-row-start+grid-column-start+grid-row-end+grid-column-end的简写形式。

可取值:

  • —— item的名字。
  • / / / —— 代表分隔线的数字或名字。
.item {
  grid-area:  |  /  /  / ;
}

举个例子:

给item命名:

.item-d {
  grid-area: header;
}

简写 grid-row-start+grid-column-start+grid-row-end+grid-column-end

.item-d {
  grid-area: 1 / col4-start / last-line / 6;
}

4、justify-self
设置item在单元格内的水平对齐方式。

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

举个例子:

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

5、align-self
值和用法和
justify-self一样,区别是align-self用来设置垂直方向的对齐方式。

6、place-self
place-selfalign-selfjustify-self的简写形式。

可取值:

  • auto —— 默认对齐模式。
  • / —— 第1个值是align-self,第2个值是justify-self,如果只有一个值,这个值会赋值给align-selfjustify-self

特殊的单位和函数

单位fr

你可能会在grid布局中使用很多分数单位,比如fr,来代表剩余空间的一部分,就像这样用,表示25%和75%:

grid-template-columns: 1fr 3fr;

这种写法比%更可靠,比如你增加了列数,就会破坏百分比的宽度,但是分数单位fr可以和其他单位更好的组合使用:

grid-template-columns: 50px min-content 1fr;

大小关键字

在设置行或列的大小时,可以用各种单位,比如pxrem%等等,还可以用一些关键字:

  • min-content: 内容的最小宽度。比如一行文字E pluribus unum,会占用的最小宽度是单词pluribus的宽度。
  • max-content: 内容的最大宽度。比如一行文字E pluribus unum,能占用的最大宽度就是一整行句子。
  • auto: 和fr类似,但优先级低于fr。
  • fit-content: 使用可用空间,但不小于min-content,不大于max-content
  • fractional units: 分数单位fr。

大小函数

  • minmax() —— 设置大小范围,minmax(最小值,最大值)。
  • min()
  • max()

repeat()函数和关键字

repeat()函数可以使写法更简洁:

grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;

/* 简洁的写法: */
grid-template-columns: repeat(8, 1fr);

/* 下面的情况更新凸显简洁: */
grid-template-columns: repeat(8, minmax(10px, 1fr));

repeat()和关键字结合时,会更加奇特:

  • auto-fill: 在一行中放入尽可能多的列,即使它们是空的。
  • auto-fit: 把所有列都放进去,增加列来填充空间即使是空的列。

这就有了CSS网格中最著名的写法,也是有史以来最伟大的CSS技巧之一:

grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

masonry

著名的瀑布流布局:

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

详情可以看这篇文章
native-css-masonry-layout-css-grid(
https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/)。

subgrid

grid-template-columns: subgrid;目前还只有 Firefox 支持,不做详细说明,有兴趣的可以看原文。

相关推荐

零基础入门AI智能体:详细了解什么是变量类型、JSON结构、Markdown格式

当品牌跳出固有框架,以跨界联动、场景创新叩击年轻群体的兴趣点,一场关于如何在迭代中保持鲜活的探索正在展开,既藏着破圈的巧思,也映照着与新一代对话的密码。在创建AI智能体时,我们会调用插件或大模型,而在...

C# 13模式匹配:递归模式与属性模式在真实代码中的性能影响分析

C#13对模式匹配的增强让复杂数据处理代码更简洁,但递归模式与属性模式的性能差异一直是开发者关注的焦点。在实际项目中,选择合适的模式不仅影响代码可读性,还可能导致执行效率的显著差异。本文结合真实测试...

零基础快速入门 VBA 系列 6 —— 常用对象(工作簿、工作表和区域)

上一节,我介绍了VBA内置函数以及如何自动打字和自动保存文件。这一节,我们来了解一下Excel常用对象。Excel常用对象Excel有很多对象,其中最常用也最重要的包括以下3个:1.Workbo...

不同生命数字的生肖龙!准到雷普!

属龙的人总在自信爆棚和自讨苦吃之间反复横跳?看完这届龙宝宝的日常我悟了。属龙的人好像天生自带矛盾体:领导力超强可人缘时好时坏,工作雷厉风行却总在爱情里翻车。关键年份的龙性格差异更大——76年龙靠谱但不...

仓颉编程语言基础-面向对象编程-属性(Properties)

属性是仓颉颉中一种强大的机制,它允许你封装对类(或接口interface、结构体struct、枚举enum、扩展extend)内部状态的访问。它看起来像一个普通的成员变量(字段),但在其背后,它通过...

Python中class对象/属性/方法/继承/多态/魔法方法详解

一、基础入门:认识类和对象1.类和对象的概念在Python中,类(class)是一种抽象的概念,用于定义对象的属性和行为,而对象(也称为实例)则是类的具体表现。比如,“汽车”可以是一个类,它有...

VBA基础入门:搞清楚对象、属性和方法就成功了一半

如果你刚接触VBA(VisualBasicforApplications),可能会被“对象”“属性”“方法”这些术语搞得一头雾水。但事实上,这三个概念是VBA编程的基石。只要理解它们之间的关系,...

P.O类型文推荐|年度编推合集(一百九十五篇)

点击左上方关注获取更多精彩推文目录2019年度编推35篇(1V1)《悖论》作者:流苏.txt(1V1)《桂花蒸》作者:大姑娘浪.txt(1V1)《豪门浪女》作者:奚行.txt...

Python参数传递内存大揭秘:可变对象 vs 不可变对象

90%的Python程序员不知道,函数参数传递中可变对象的修改竟会导致意想不到的副作用!一、参数传递的本质:对象引用传递在Python中,所有参数传递都是对象引用的传递。这意味着函数调用时传递的不是对...

JS 开发者必看!TC39 2025 最新动向,这些新语法要火?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。TC39第...

2025 年值得尝试的 5 个被低估的 JavaScript 库

这些JavaScript库可能不会在社交媒体或HackerNews上流行起来,但它们会显著提高您的工作效率和代码质量。JavaScript不再只是框架。虽然React、Vue和Sv...

Python自动化办公应用学习笔记30—函数的参数

一、函数的参数1.形参:o定义:在函数定义时,声明在函数名后面括号中的变量。o作用:它们是函数内部的占位符变量,用于接收函数被调用时传入的实际值。o生命周期:在函数被调用时创建,在函数执...

16种MBTI人格全解析|测完我沉默了三秒:原来我是这样的人?

MBTI性格测试火了这么久,你还不知道自己是哪一型?有人拿它当社交话题,有人拿它分析老板性格,还有人干脆当成择偶参考表。不废话,今天我一次性给你整理全部16种MBTI人格类型!看完你不仅能知道自己是谁...

JS基础与高级应用: 性能优化

在现代Web开发中,性能优化已成为前端工程师必须掌握的核心技能之一。本文从URL输入到页面加载完成的全过程出发,深入分析了HTTP协议的演进、域名解析、代码层面性能优化以及编译与渲染的最佳实践。通过节...

爱思创CSP-J/S初赛模拟赛线上开赛!助力冲入2024年CSP-J/S复赛!

CSP-J/S组初赛模拟赛爱思创,专注信奥教育19年,2022年CSP-J/S组赛事指定考点,特邀NOIP教练,开启全真实CSP-J/S组线上初赛模拟大赛!一、比赛对象:2024年备考CSP-J/S初...