告别浮动,轻松掌握 CSS Flexbox 布局 – wiki基地


告别浮动,轻松掌握 CSS Flexbox 布局

在现代 Web 开发中,布局是构建用户界面的基石。从简单的元素排列到复杂的响应式网格,布局决定了内容如何呈现在屏幕上。然而,长期以来,CSS 布局一直是让开发者头疼的问题。我们依赖于浮动(float)、行内块(inline-block)甚至表格(display: table)等技术来模拟所需的布局效果,这些方法往往伴随着各种问题:清除浮动(clearfix)的麻烦、垂直居中的噩梦、响应式调整时的局限性以及代码的脆弱性。

想象一下,你正在尝试让一个盒子在容器中垂直居中,或者让一组元素在空间不足时自动换行并均匀分布。使用传统方法,这可能需要多层嵌套、负外边距、百分比计算,甚至是 JavaScript 的辅助。这些技巧就像是在使用螺丝刀敲钉子一样,虽然勉强能用,但远非最优解。

幸运的是,随着 CSS3 的发展,现代布局模块应运而生,彻底改变了我们处理布局的方式。其中最重要、最常用的一个,就是我们今天的主角——Flexbox (弹性盒子布局)。Flexbox 专为解决一维布局问题而设计,无论你的元素是水平排列还是垂直排列,Flexbox 都能提供强大而直观的工具来控制它们的对齐、分布和顺序。告别浮动带来的种种困扰,让我们一起轻松掌握 Flexbox 布局,迈向更简洁、更灵活、更强大的 CSS 世界。

传统布局的痛点:浮动、行内块与那些年踩过的坑

在深入 Flexbox 之前,回顾一下我们是如何走到这一步的,有助于我们理解 Flexbox 的价值。

1. 浮动 (Float):为文字环绕而生,却被滥用于布局

float 属性最初的设计目的是让文字内容能够环绕图片等元素。但由于其能够将元素从文档流中“部分”脱离,并使后续块级元素填补其位置(文字内容仍会避开),它被广泛应用于创建多列布局。

  • 优点: 可以实现简单的左右排列。
  • 缺点:
    • 父元素高度塌陷: 浮动元素脱离了正常文档流,导致其父元素无法感知其高度,父元素可能会“塌陷”,需要使用 clearfix 等技巧来修复。
    • 破坏文档流: 浮动元素会影响后续非浮动元素的布局。
    • 垂直对齐困难: float 对垂直对齐几乎无能为力。
    • 顺序限制: 元素的视觉顺序通常受限于其在 HTML 中的源顺序。
    • 响应式挑战: 在不同屏幕尺寸下调整浮动元素的宽度和间距通常需要复杂的计算和媒体查询。

2. 行内块 (Inline-block):水平排列的另一选择,但有副作用

将元素的 display 属性设置为 inline-block 可以让元素像行内元素一样在同一行排列,同时又保留块级元素的特性(可以设置宽高、上下外边距等)。这比浮动更适合水平菜单或一系列卡片排列。

  • 优点: 实现水平排列相对简单,不会导致父元素高度塌陷。
  • 缺点:
    • 空白间隙问题: inline-block 元素之间会保留 HTML 代码中的空白符(空格、换行、制表符)产生的间隙,这通常不是我们想要的,需要通过去除 HTML 中的空白或使用 CSS hack (如设置 font-size: 0 在父元素上) 来解决。
    • 垂直对齐仍然麻烦: 虽然 vertical-align 属性对 inline-block 有效,但其行为有时不够直观,尤其是当元素高度不同时,实现底部对齐、顶部对齐或居中对齐需要反复试验。

3. 定位 (Positioning):强大但容易脱离掌控

position: absoluteposition: relative 配合使用可以实现复杂的定位效果,包括垂直居中。

  • 优点: 可以实现精确的元素定位,常用于覆盖、模态框等。
  • 缺点:
    • 完全脱离文档流: position: absolute 元素完全脱离文档流,不再占用空间,可能导致其他元素覆盖或布局混乱。
    • 依赖父元素定位: absolute 定位是相对于最近的非 static 定位祖先元素。
    • 不适合大规模布局: 难以用来构建整个页面的网格或动态分配空间的布局。

这些传统方法虽然在没有 Flexbox 的时代发挥了重要作用,但它们的局限性和所需的额外技巧使得布局工作变得繁琐、容易出错,尤其是在需要构建灵活、响应式的界面时。是时候拥抱现代布局工具了!

Flexbox 核心概念:容器与项目,主轴与交叉轴

Flexbox 布局是基于容器项目的概念。

  1. Flex 容器 (Flex Container): 通过将元素的 display 属性设置为 flexinline-flex,使其成为一个 Flex 容器。直接子元素将自动成为 Flex 项目。
  2. Flex 项目 (Flex Items): Flex 容器的所有直系子元素都会成为 Flex 项目。Flexbox 的所有布局魔法都发生在 Flex 项目之间以及它们与其 Flex 容器之间。

Flexbox 布局总是沿两条轴线进行:

  • 主轴 (Main Axis): Flex 项目沿主轴排列。主轴的方向由容器的 flex-direction 属性决定。它可以是水平的(从左到右或从右到左)或垂直的(从上到下或从下到上)。
  • 交叉轴 (Cross Axis): 与主轴垂直的轴线。如果主轴是水平的,交叉轴就是垂直的;如果主轴是垂直的,交叉轴就是水平的。

理解主轴和交叉轴是掌握 Flexbox 的关键。几乎所有的 Flexbox 属性都与这两条轴线有关。

Flex 容器属性:掌控全局的指挥官

Flex 容器的属性负责设定 Flexbox 布局的基本行为,包括项目的排列方向、是否换行以及如何在主轴和交叉轴上对齐。

1. display

  • flex 将元素设置为块级 Flex 容器。
  • inline-flex 将元素设置为行内级 Flex 容器。容器本身的行为类似于 inline-block,但其内部的子元素遵循 Flexbox 布局。

绝大多数情况下,我们使用 display: flex;

2. flex-direction

定义主轴的方向,从而决定 Flex 项目的排列方向。

  • row (默认值): 主轴为水平方向,起点在左端。项目从左向右排列(在ltr书写模式下)。
  • row-reverse 主轴为水平方向,起点在右端。项目从右向左排列。
  • column 主轴为垂直方向,起点在上端。项目从上向下排列。
  • column-reverse 主轴为垂直方向,起点在下端。项目从下向上排列。

这是一个非常重要的属性,它直接定义了你的“一维”布局是水平的还是垂直的。

css
.container {
display: flex;
flex-direction: row; /* 或 column, row-reverse, column-reverse */
}

3. flex-wrap

定义 Flex 项目在一条轴线上排不下时,是否换行以及如何换行。

  • nowrap (默认值): 不换行。所有 Flex 项目都试图挤在同一行或同一列中,可能会导致溢出容器。
  • wrap 换行。当空间不足时,项目会换到新的一行或一列。换行方向与主轴方向垂直。
  • wrap-reverse 反向换行。当空间不足时,项目会换到新的一行或一列,但新行/列会堆叠在旧行/列的上方或左方(取决于主轴方向)。

flex-wrap: wrap; 是实现响应式网格布局或卡片列表的关键。

css
.container {
display: flex;
flex-wrap: wrap; /* 或 nowrap, wrap-reverse */
}

4. flex-flow

这是 flex-directionflex-wrap 的简写属性,顺序不固定。

  • 示例: flex-flow: row wrap; 等同于 flex-direction: row; flex-wrap: wrap;

css
.container {
display: flex;
flex-flow: column wrap;
}

5. justify-content

定义了 Flex 项目在主轴上的对齐方式以及空间分布。

  • flex-start (默认值): 项目靠主轴的起始端对齐。
  • flex-end 项目靠主轴的结束端对齐。
  • center 项目在主轴中心对齐。
  • space-between 首个项目和末个项目分别靠向主轴的起始和结束端,剩余空间平均分布在项目之间。项目之间的间隙相等。
  • space-around 每个项目两侧都有相等的空间。视觉上,项目之间的间隙是项目与容器边缘间隙的两倍。
  • space-evenly 所有项目之间以及项目与容器边缘之间的空间都完全相等。

这是实现水平居中、两端对齐、均匀分布等效果的利器。

css
.container {
display: flex;
justify-content: center; /* 或 flex-start, flex-end, space-between, space-around, space-evenly */
}

6. align-items

定义 Flex 项目在交叉轴上的对齐方式,适用于单行单列的 Flex 容器(即 flex-wrap: nowrap 或即使换行也只有一行/列的情况)。

  • stretch (默认值): 如果项目没有设置高度或宽度(取决于交叉轴方向)或者设置为 auto,它们将拉伸以填满容器在交叉轴方向上的可用空间。
  • flex-start 项目靠交叉轴的起始端对齐。
  • flex-end 项目靠交叉轴的结束端对齐。
  • center 项目在交叉轴中心对齐。
  • baseline 项目根据其内容的基线对齐。

配合 justify-content: center; 可以轻松实现元素的水平垂直双向居中(当容器只有一行/列时)。

css
.container {
display: flex;
align-items: center; /* 或 stretch, flex-start, flex-end, baseline */
}

7. align-content

定义了多行/多列 Flex 项目(当 flex-wrap: wrap; 且产生了多行/多列)在交叉轴上的对齐方式以及行/列之间的空间分布。它控制的是整个“内容区域”(即所有 Flex 行/列组成的整体)在容器交叉轴上的对齐。

  • stretch (默认值): 所有行/列会拉伸,以充分占用容器在交叉轴上的可用空间。
  • flex-start 所有行/列靠交叉轴的起始端堆叠对齐。
  • flex-end 所有行/列靠交叉轴的结束端堆叠对齐。
  • center 所有行/列在交叉轴中心堆叠对齐。
  • space-between 首行/列和末行/列分别靠向交叉轴的起始和结束端,剩余空间平均分布在行/列之间。
  • space-around 每行/列两侧都有相等的空间。

注意:align-content 只有在容器有多行/多列时才有效。如果只有一行(flex-wrap: nowrap; 或者虽然 wrap 但空间足够只形成一行),align-content 将不起作用,此时交叉轴的对齐由 align-items 控制。

css
.container {
display: flex;
flex-wrap: wrap; /* 必须换行才能看到效果 */
align-content: space-between; /* 或 stretch, flex-start, flex-end, center, space-around */
}

Flex 项目属性:控制个体行为的魔法棒

Flex 项目的属性控制着单个项目在 Flex 容器内的表现,包括其顺序、伸缩能力以及在交叉轴上的自对齐方式。

1. order

定义 Flex 项目的排列顺序。默认值为 0。数字越小,排列越靠前。可以设置负值。

  • 示例: 一个容器内有三个项目A, B, C (默认 order 都是 0)。如果给项目 B 设置 order: -1;,它将排在最前面。如果给项目 C 设置 order: 1;,它将排在最后面。最终顺序可能是 B, A, C。

这个属性非常有用,可以在不改变 HTML 结构的情况下改变元素的视觉顺序,这对于响应式设计尤其方便(例如,在小屏幕上改变侧边栏和主内容的顺序)。

“`css
.item {
order: 1; / 默认是 0 /
}

.item-important {
order: -1; / 会排在 order 0 的项目之前 /
}
“`

2. flex-grow

定义 Flex 项目的放大比例。当 Flex 容器在主轴方向上有剩余空间时,flex-grow 大于 0 的项目会根据其设置的比例分配这些剩余空间。默认值为 0 (不放大)。

  • 示例: 容器内有三个项目 A, B, C。A 的 flex-grow 是 1,B 是 1,C 是 2。如果容器有 100px 剩余空间,A 和 B 各会分配到 100px / (1 + 1 + 2) * 1 = 25px 的增长空间,C 会分配到 100px / (1 + 1 + 2) * 2 = 50px 的增长空间。

flex-grow: 1; 是让项目填充剩余空间的常用方法。

“`css
.item {
flex-grow: 1; / 占据所有剩余空间的均等一部分 /
}

.item-double-size {
flex-grow: 2; / 占据剩余空间的两倍部分 /
}
“`

3. flex-shrink

定义 Flex 项目的缩小比例。当 Flex 容器在主轴方向上空间不足以容纳所有项目时,flex-shrink 大于 0 的项目会根据其设置的比例收缩。默认值为 1 (允许收缩)。

  • 示例: 容器宽度为 300px,有三个项目,每个项目原本宽度为 150px,总宽度 450px,超出了 150px。如果三个项目的 flex-shrink 都是 1,它们将平均收缩 150px / 3 = 50px。如果项目 A 的 flex-shrink 是 1,B 是 1,C 是 2,那么总的收缩“能力”是 1+1+2=4。A 和 B 各承担 (1/4) * 150px 的收缩,C 承担 (2/4) * 150px 的收缩。

flex-shrink: 0; 可以阻止项目收缩,即使空间不足。

“`css
.item {
flex-shrink: 1; / 默认值,允许收缩 /
}

.item-no-shrink {
flex-shrink: 0; / 不允许收缩 /
}
“`

4. flex-basis

定义了在分配剩余空间之前,项目的初始主轴尺寸。它可以是一个长度值(如 100px50%)或关键字 auto (默认值)。

  • auto 项目的初始尺寸取决于其 widthheight 属性(取决于主轴方向)。如果没有设置 widthheight,则基于内容决定大小。
  • 长度值: 项目的初始尺寸被固定为该值,忽略其 widthheight 设置。

理解 flex-basis 的关键在于它定义了项目在伸缩(grow/shrink)之前的基础大小。

“`css
.item {
flex-basis: 100px; / 初始宽度/高度为 100px /
}

.item-auto {
flex-basis: auto; / 初始尺寸取决于 width/height 或内容 /
}
“`

5. flex

这是 flex-grow, flex-shrink, 和 flex-basis简写属性,顺序为 flex-grow flex-shrink flex-basis

  • 常用值:
    • flex: auto;:等同于 flex: 1 1 auto;。允许项目放大和缩小,初始尺寸根据内容或 width/height 决定。
    • flex: none;:等同于 flex: 0 0 auto;。项目既不放大也不缩小,保持其内容或 width/height 决定的原始尺寸。
    • flex: 0 auto;:等同于 flex: 0 1 auto;。项目不放大,但允许收缩,初始尺寸根据内容或 width/height 决定。
    • flex: 1;:等同于 flex: 1 1 0%;。允许项目放大和收缩,初始尺寸为 0,这意味着它会尽可能多地占用可用空间(根据 grow 比例)。这是让项目填充剩余空间的常见简写。

建议优先使用 flex 简写属性,它更简洁易读。例如,flex: 1; 是实现“弹性”填充布局中最常用的设置。

“`css
.item {
flex: 1; / 伸缩性最强,会尝试填充空间 /
}

.item-fixed {
flex: 0 0 100px; / 固定大小 100px,不伸缩 /
}
“`

6. align-self

允许单个 Flex 项目有区别于其父容器 align-items 设置的对齐方式。它可以覆盖容器的 align-items 属性。

  • auto (默认值): 继承父容器的 align-items 属性。如果没有父容器,则为 stretch
  • flex-start 靠交叉轴的起始端对齐。
  • flex-end 靠交叉轴的结束端对齐。
  • center 在交叉轴中心对齐。
  • baseline 根据基线对齐。
  • stretch 拉伸以填满容器。

这对于在同一行/列中使某个项目独特对齐非常方便。

css
.item {
align-self: center; /* 覆盖容器的 align-items 设置,在交叉轴上居中 */
}

Flexbox 实用技巧与常见布局案例

掌握了 Flex 容器和项目的属性后,Flexbox 的强大之处才真正显现出来。下面是一些使用 Flexbox 轻松实现常见布局效果的例子。

1. 水平垂直居中 (终结居中噩梦)

这是 Flexbox 最令人称道的用途之一。只需在容器上设置两行代码:

css
.container {
display: flex;
justify-content: center; /* 主轴居中 (水平) */
align-items: center; /* 交叉轴居中 (垂直) */
height: 300px; /* 容器需要有高度 */
}

无论子元素大小如何变化,都能轻松居中。如果主轴是垂直的 (flex-direction: column;),那么 justify-content: center; 实现垂直居中,align-items: center; 实现水平居中。

2. 创建导航菜单

创建水平或垂直导航菜单非常简单:

“`css
.nav {
display: flex;
list-style: none; / 移除列表默认样式 /
padding: 0;
margin: 0;
}

.nav li {
margin-right: 10px; / 项目之间的间距 /
}

/ 如果需要垂直导航 /
.nav-vertical {
display: flex;
flex-direction: column;
}

.nav-vertical li {
margin-bottom: 10px;
margin-right: 0;
}
“`

使用 justify-content 还可以控制导航项的分布方式,例如 justify-content: space-around; 可以让导航项均匀分布在容器宽度内。

3. 响应式卡片布局

使用 flex-wrap: wrap; 可以轻松创建在不同屏幕尺寸下自动调整列数的卡片布局。

“`html

Card 1
Card 2
Card 3
Card 4
Card 5

“`

“`css
.card-container {
display: flex;
flex-wrap: wrap; / 允许换行 /
gap: 20px; / 使用 gap 属性设置项目之间的间距,比 margin 更好用 /
}

.card {
flex: 0 0 300px; / 固定卡片宽度 300px,不放大也不收缩 /
/ 或者使用 flex: 1 1 300px; 让卡片在空间足够时宽度至少 300px 并尽量放大 /
/ 或者使用 flex: 1 1 auto; 然后设置 min-width: 300px; max-width: 400px; 来控制范围 /
border: 1px solid #ccc;
padding: 20px;
box-sizing: border-box; / 让 padding 和 border 不计入 flex-basis /
}

/ 可选:使用媒体查询调整卡片宽度以适应不同屏幕 /
@media (max-width: 600px) {
.card {
flex-basis: 100%; / 小屏幕下卡片占满一行 /
}
}
“`

这里,flex: 0 0 300px; 设置了卡片的固定宽度为 300px。当一行放不下多个 300px 的卡片时,flex-wrap: wrap; 会让它们自动换行。gap 属性提供了比 margin 更方便的方式来处理项目间隙,它只在项目之间产生间隙,而不会在项目和容器边缘之间产生。

更灵活的方式是设置 flex: 1 1 300px; 结合媒体查询调整基础宽度,或者使用 flex: 1; min-width: 300px; 来让项目在空间足够时放大,但最小宽度不低于 300px,不足时再换行。

4. 顶部固定,内容滚动的布局

“`html

固定头部

滚动内容区

固定底部

“`

“`css
.layout-container {
display: flex;
flex-direction: column; / 主轴垂直 /
height: 100vh; / 容器高度占满视口 /
}

header, footer {
flex: 0 0 auto; / 固定大小,不伸缩 /
background-color: #f0f0f0;
padding: 10px;
}

main {
flex: 1; / 占据所有剩余空间 /
overflow-y: auto; / 内容溢出时显示滚动条 /
padding: 10px;
}
“`

这里利用了 flex-direction: column; 将主轴设为垂直方向。header 和 footer 设置 flex: 0 0 auto; 固定高度(auto 会根据内容决定),不参与伸缩。main 设置 flex: 1; 则占据了容器内的所有剩余垂直空间,并设置 overflow-y: auto; 实现内部滚动。

5. 表单项对齐

使用 Flexbox 可以轻松对齐表单中的标签和输入框。

“`html



“`

“`css
.form-layout {
display: flex;
flex-direction: column; / 项目垂直堆叠 /
gap: 15px; / 组之间的间距 /
}

.form-group {
display: flex; / 使 label 和 input 成为 Flex 项目 /
align-items: center; / 在交叉轴上垂直居中对齐 (基于文本基线通常是更好的选择) /
}

.form-group label {
flex: 0 0 80px; / 固定 label 宽度为 80px,不伸缩 /
margin-right: 10px;
}

.form-group input {
flex: 1; / input 占据剩余空间 /
}

.form-group button {
/ 如果按钮单独一行或需要特定对齐 /
/ 对于 submit 按钮,如果它在 form-group 容器内,可以给其父级 form-group 设置 justify-content /
}

/ 例如,让提交按钮居中 /
.form-layout .form-group:last-child {
justify-content: center; / 最后一个 form-group 内部项目居中 /
}
“`

这里利用了嵌套 Flexbox。外部容器 .form-layout 使用 flex-direction: column; 使每个 .form-group 垂直排列。每个 .form-group 又是一个 Flex 容器,使用 display: flex; 使其内部的 labelinput 水平排列,并通过 align-items: center;baseline 使它们垂直对齐。给 label 设置固定的 flex-basis 并禁止其伸缩 (flex: 0 0 80px;),让 input 设置 flex: 1; 占据剩余空间,从而实现了标签和输入框的对齐效果。

Flexbox vs. Grid:孪生兄弟,各有所长

与 Flexbox 同时出现的另一重要布局模块是 CSS Grid (网格布局)。虽然它们都能创建复杂的布局,但侧重点不同:

  • Flexbox: 适用于一维布局,即沿着单一行或单列对齐和分布空间。它更侧重于容器内项目的内容相互关系,动态调整项目的尺寸和位置以适应可用空间。非常适合组件内部的布局,如导航条、卡片、表单组等。
  • Grid: 适用于二维布局,即同时控制行和列的对齐与分布。它更侧重于页面的整体结构,将页面划分为多个区域(网格),然后将元素放置到这些网格区域中。非常适合构建整个页面的主布局框架。

简而言之,Flexbox 是处理“一组项目”的利器,而 Grid 是搭建“整个页面骨架”的工具。它们并非互斥,而是互补的。在实际开发中,你经常会将它们结合使用:使用 Grid 构建页面的宏观布局,然后在 Grid 区域内的组件内部使用 Flexbox 进行微观布局。

告别浮动:为什么 Flexbox 是更好的选择?

现在我们可以清楚地看到 Flexbox 相较于传统浮动布局的巨大优势:

  1. 意图明确: Flexbox 是专门为布局而设计的模块,不像 float 是滥用其他属性。
  2. 逻辑清晰: 基于容器与项目、主轴与交叉轴的概念,使得布局逻辑更加直观易懂。
  3. 轻松对齐: justify-contentalign-items/align-content 提供了强大而简单的对齐手段,垂直居中不再是难题。
  4. 空间管理: flex-growflex-shrink 使得弹性地分配和占用剩余空间变得异常容易,无需复杂的百分比计算。
  5. 顺序控制: order 属性可以在不改变 HTML 结构的情况下调整视觉顺序,增强了灵活性和可访问性(HTML 顺序仍应保持逻辑结构)。
  6. 避免副作用: Flex 项目默认不会完全脱离文档流(除非使用绝对定位),避免了父元素塌陷等问题。
  7. 天生响应式: flex-wrap 结合 Flex 项目的伸缩性,使得创建响应式布局变得自然而然。

使用 Flexbox,你可以用更少的代码实现更复杂、更灵活的布局效果,同时代码更易读、易维护、更健壮。

兼容性与未来

Flexbox 在现代浏览器中的支持已经非常完善,包括主流桌面和移动浏览器。尽管如此,了解一些旧版本浏览器的前缀(如 -webkit-box, -webkit-flex 等)和一些旧的规范可能会有帮助(特别是处理一些遗留项目时),但对于新项目,通常可以直接使用标准语法。对于需要兼容极少数老旧浏览器的场景,可能需要考虑使用 Polyfill 或提供基于浮动的备用布局,但这种情况越来越少见。

Flexbox 是现代 CSS 布局体系的重要组成部分,与 Grid 布局、逻辑属性、Gap 属性等一起,正在逐步取代传统的布局方法,使 CSS 布局变得更加强大和友好。

总结

Flexbox 是一个强大、灵活且相对容易掌握的 CSS 布局模块。它通过引入 Flex 容器和 Flex 项目的概念,以及主轴和交叉轴的思维模式,提供了一套优雅的解决方案来处理一维空间的元素排列、对齐和空间分配问题。

我们详细探讨了 Flex 容器的属性 (display, flex-direction, flex-wrap, flex-flow, justify-content, align-items, align-content) 和 Flex 项目的属性 (order, flex-grow, flex-shrink, flex-basis, flex, align-self),并通过具体的案例展示了如何利用这些属性实现垂直居中、弹性导航、响应式卡片列表、固定头部/底部布局以及表单对齐等常见需求。

与传统的浮动、行内块等方法相比,Flexbox 提供了更清晰的逻辑、更强大的功能和更少的“副作用”,极大地简化了布局工作,特别是对于构建现代的、响应式的用户界面。

告别那些复杂的浮动清除和垂直对齐 hack 吧!投入 Flexbox 的怀抱,你将发现 CSS 布局从未如此轻松和愉快。现在,是时候动手实践,亲自体验 Flexbox 带来的便利和强大了!从简单的容器开始,尝试调整各种属性,看看它们如何影响你的布局。随着练习的深入,你将越来越熟练地运用 Flexbox,成为布局大师。

记住,Flexbox 和 Grid 是现代 CSS 布局的两大支柱,掌握它们是成为一名优秀前端开发者的必备技能。祝你在 Flexbox 的学习旅程中一帆风顺!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部