Flex布局和Grid布局详解

在前端样式编写中,Flex 布局早已成为日常开发的“标配”。无论是 display: flex 还是 display: grid,它们都为我们提供了强大的自适应能力和灵活的布局方式。但如果对 Flex 的理解仅停留在 align-itemsjustify-content 这些常见属性的简单使用,那么在面对复杂布局或一些“看似奇怪”的样式问题时,往往会陷入困惑:为什么设置了 height 却不生效?为什么元素没有按预期填满空间?又或者,什么时候该用 Grid,什么时候该用 Flex?

事实上,Flex 和 Grid 并不仅仅是“用来排版”的工具,它们背后各自有一套完整的布局模型和计算规则。理解这些规则,不仅能帮你写出更简洁、可控的样式,还能让你在调试布局问题时少走很多弯路。本文将系统梳理 display: flexdisplay: grid 的核心原理、关键差异,以及它们在不同布局需求下的最佳使用方式,帮助你真正掌握现代 CSS 布局的底层逻辑。

Flex弹性盒子布局

display: flex ,通常被称为flexbox。它是一种一维的布局模型。“一维”是指一个flexbox 一次只能处理一个维度上的元素布局,它只能控制flex-direction设置的主轴方向的元素布局,即行或者列。
在这里插入图片描述

相比下display: grid网格布局就可以同时处理行和列上的布局,因此网格布局也被称为二维布局。

下面本文将从实际开发的场景出发,让你实际感受一下这两个布局的直观差别:

在使用 flex 布局的时候,很容易遇到元素换行后,换行位置出现很大的空余截断的场景,如下图所示。出现这种情况的原因在于,flex布局并不能精准控制行和列的显示,当屏幕不足以放下下一个元素的时候,flex会直接将下一个元素放到下一列 或 行显示(这个却决于你的主轴设置)
在这里插入图片描述

同样的场景下,grid 布局就显得更为合理,如下图。
在这里插入图片描述

鼠标放在元素上,仔细观察,我们就能发现 grid 布局的精妙之处,你可以通过设置grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)) 实现列的自适应扩展,多个块共同划分多余的内容,这样在视觉呈现上使其更加合理。除此之外,你还可以通过设置grid-template-row: 来控制行的排列,而这就是所谓的二维布局。
在这里插入图片描述

Flex 元素上的三个基本属性

一个容器的 display 属性值为 flex 或者 inline-flex,容器中的直系子元素就是 flex 元素。flex 容器中的所有 flex 元素不会在主轴拉伸,但是可以缩小。这也就是为什么,在不设置flex-wrap: wrap,子元素未设置flex-shrinkflex-basis,且容器的在主轴线上大小固定时,子元素的大小会随着子元素数量的增多而缩小的原因。
在这里插入图片描述

为了更好的控制 flex 元素,CSS 引入了三个属性:flex-growflex-shrinkflex-basis。这几个属性本上就是改变了 flex 容器的"可用空间"行为,每个属性都定义了子元素该如何去利用可用空间,如何在空间不足时去分配空间——flex 容器里除了元素所占的空间以外的富余空间就是可用空间。下面开始讲解这三个属性,基于主轴为row的场景进行举例讲解。

  • flex-basis定义了 flex 元素的初始空间大小

    • auto(默认):当flex-basis: auto时,浏览器会先检测这个元素是否具有确定的尺寸,如果元素设置了 width 为 100px,则约等于flex-basis: 100px。 如果没有设定尺寸,则flex-basis 的值采用元素的内容尺寸,这也就是为什么我们不设置元素大小的时候,只为父元素设置display: flex时,内容多的元素会更大
    • 0(特殊情况):flex-basis: 0 是 Flex 布局里一个非常关键但也最容易被忽略的点,其表示:**元素的初始尺寸按 0 计算,完全忽略内容大小,只按剩余空间分配。**这也意味着所有子元素都在同一起跑线,其能分配的内容大小取决于flex-grow的大小。
    • 100px(固定值)
  • flex-grow定义了当容器有剩余空间时,这个元素“愿意放大”的比例,值**>= 0**,默认为1。eg: 一个 flex 容器内有a、b两个子元素,a元素只设置了 flex-grow: 2,b元素未设置任何属性,此时a元素的大小为容器width * (2/1+2)

  • flex-shrinkflex-grow相反,该属性是作用于当容器空间不能满足所有子元素的flex-basis时,每个元素“愿意被挤压”的程度。值**>= 0,默认为1。计算公式为:(所有子元素基础宽度之和 - 容器宽度) * (当前子元素的flex-shrink值 / 所有子元素的flex-shrink值之和)0特殊**意味着不参与布局。

这个三个属性缩写:flex: <flex-grow> <flex-shrink> <flex-basis> 常见 flex: 1 等价于 flex: 1 1 0flex: 2 等价于 flex: 2 1 0

Flex 容器的对齐规则

align-items 属性可以使元素在交叉轴(与主轴垂直的方向)方向对齐。

justify-content属性用来使元素在主轴方向上对齐

Flex 元素独立的对齐规则

除了对容器整体对齐规则做设置外,我们还可以对 flex 容器内指定的元素进行独立调整。

align-self 调整元素在交叉轴上的对齐方式,覆盖容器的align-items的属性,值与其相同。注意:任何 flex元素的交叉轴方向 margin 值设置为 auto,则会忽略 align-self

Grid 网格布局

display: grid,称为CSS 网格布局。它与flex弹性布局的区别除了前面所说的一维和二维的区别外,还有一个关键的区别:在网格布局中,你需要在容器上设置大部分尺寸规范,设置轨道然后将元素放入其中。在弹性盒子中,虽然你创建了弹性容器并设置了该级别的方向,但是对元素大小的任何控制都需要在元素本身之上进行。从grid的基本属性设置grid-template-columnsgrid-template-rows就可以看出。

基本概念

网格布局中最关键的就是理解网格的行和列的意义,如下图。行和列交叉的区域叫“单元格”,即元素。
在这里插入图片描述

在 Grid 布局里,定位是基于 网格线(grid line) 而不是网格单元。

布局结构: 
| 1 | 2 | 3 |
网格线编号: 
1   2   3   4
|---|---|---|

3列会有 4条网格线,元素通过 起始线 → 结束线 来确定位置。

属性介绍

下列的xx-columnsxx-rows的区别只是对应轴线的不同。

grid-template-columns 属性, grid-template-rows 属性
  • 100px 100px 100px:指定了三个元素大小,每个元素100px。这是通过为每个元素设置固定的大小的px
  • max-content:表示元素按照内容能够达到的最大尺寸进行布局,不会因为容器限制而主动换行或收缩
  • min-content:表示元素在不溢出的情况下可以缩小到的最小尺寸
  • fit-content():表示元素宽度根据内容自适应,但不会超过容器限制。举例:grid-template-columns: fit-content(300px);含义:列宽 = min(max-content, 300px)
  • 1fr:用于表示比例关系,两列的宽度分别为1fr2fr,就表示后者是前者的两倍。与绝对长度单位结合使用,会非常方便如:150px 1fr 2fr 表示第一列的宽度为150px,第二列的宽度是第三列的一半。
  • minmax(): 产生一个长度范围,表示长度就在这个范围之中。
  • auto:表示由浏览器自己决定长度。
  • repeat(): 接收两个参数,第一个参数是重复元素的个数,第二个参数是重复元素的大小,与前面介绍的参数一致
    • 第一个参数 :
      • 1(具体数字):表示固定的重复个数。
      • auto-fill: 表示自动填充,有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,此时可以使用这个参数。
      • auto-fit:行为与auto-fill相同,区别在于auto-fill不会保留空列,即如果容器一行能放5个元素,现在只有3个元素,此时auto-fill的行为会呈现[ item ][ item ][ item ][ ][ ]auto-fit会将剩余空间分配给这三个元素,呈现[ item ][ item ][ item ]
gap 属性
  • grid-row-gap:设置行间距,grid-row-gap: 20px;
  • grid-column-gap: 设置列间距,grid-column-gap: 20px;
  • grid-gap: <grid-row-gap> <grid-column-gap>: grid-gap: 20px 20px;
grid-auto-flow 属性

划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是"先行后列",即先填满第一行,再开始放入第二行。

grid-auto-flow: column; 默认值是row,即"先行后列"。也可以将它设成column,变成"先列后行"

grid-auto-flow: row dense; 加上dense表示尽量填满空格

grid-column 属性, grid-row 属性

grid-column: start / end;表示:从第 start 条列线,到第 end 条列线。

.item {
  grid-column: 1 / 3;
}

效果:

|------|-----|-------|
|  column1   |column3|
grid-auto-columns属性,grid-auto-rows属性

当网格项目被放到一个没有显式定义的行或列时,浏览器会自动创建新的行或列,这些自动生成的轨道尺寸就由这两个属性决定

例如:

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

这里只定义了 2列,如果子元素被放到第三列

.item {
  grid-column: 3;
}

此时浏览器会 自动创建一列,这个就是叫隐式网格列,它的宽度由:grid-auto-columns控制。

设置格式:grid-auto-columns: 100px;

网格布局元素独立的对齐规则

除了Flex元素的align-self外,网格布局中的块元素还支持justify-self调整元素在主轴上的对齐方式,覆盖容器的justify-items的属性,值与其相同。

什么时候用 Flex?什么时候用 Grid?

Flex: 横向排列(导航栏)、垂直居中、按比例分配空间、简单的排版

Grid: 卡片布局、后台表格布局、仪表盘、复杂排版

参考资料

https://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html

https://developer.mozilla.org/zh-CN/docs/Web/CSS/Guides/Flexible_box_layout

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐