CSS布局-弹性盒布局(Flexbox)

177 阅读14分钟

1. 简介

CSS 布局经历了多个阶段的发展。早期,我们使用表格(table)进行布局,但表格布局存在语义不清晰、维护困难等问题。后来,基于浮动(float)的布局方式流行起来,它允许元素在文档流中浮动,实现多列布局。然而,浮动布局也有其局限性,例如清除浮动的复杂性,以及在处理复杂布局时容易出现的布局混乱问题。

Flexbox 的出现为网页布局带来了新的解决方案。它提供了一种更加直观、灵活的方式来排列和对齐元素,尤其适用于响应式设计。

2. Flexbox原理

Flexbox 布局基于一个弹性容器(flex container)和多个弹性子元素(flex item)。弹性容器通过设置display: flex属性来创建。一旦一个元素被设置为弹性容器,其直接子元素就会成为弹性子元素。

Flexbox 的核心原理是通过弹性容器的属性来控制弹性子元素的排列方向、对齐方式、伸缩比例等。弹性容器有两条轴:主轴(main axis)和交叉轴(cross axis)。主轴的方向由flex - direction属性决定,可以是水平方向(默认)或垂直方向。交叉轴则与主轴垂直。通过设置不同的属性,我们可以精确地控制弹性子元素在这两条轴上的表现。

  • Flexbox是一种基于容器与项目关系的一维布局模型。
  • 它通过设置容器的display: flex;或inline-flex;来启用弹性盒布局,此时容器内的子元素即成为弹性项目。
  • 容器负责定义主轴和交叉轴方向、对齐方式等整体布局规则;项目则根据容器设定以及自身属性进行排列。

3. Flexbox优缺点

3.1 优点

  1. 简单灵活:相比传统的布局方式,Flexbox 的语法更加简洁,能够快速实现复杂的布局效果。例如,实现水平或垂直居中对齐,在 Flexbox 中只需简单的几行代码即可完成。
  2. 响应式设计:Flexbox 对响应式设计支持良好。通过设置不同的属性值,可以轻松地使布局在不同屏幕尺寸下自适应调整。例如,在小屏幕上可以将多列布局改为单列布局。
  3. 自动排列:Flexbox 能够自动分配弹性子元素的空间,根据容器的大小和子元素的属性,自动调整子元素的尺寸和位置。

3.2 缺点

  1. 浏览器兼容性:虽然现代浏览器对 Flexbox 的支持已经很好,但在一些旧版本的浏览器(如 IE10 及以下)中,对 Flexbox 的支持存在差异,需要使用特定的前缀或采用其他兼容方式。
  2. 复杂布局的局限性:对于一些非常复杂的嵌套布局,Flexbox 可能会变得难以管理。在这种情况下,配合其他布局方式(如网格布局 Grid)可能会更好。

4. Flexbox属性解析

4.1 作用在flex容器上的属性

4.1.1 display

  • **作用:**指定一个弹性容器。
  • 取值:
    • flex: 块级弹性容器
    • inline-flex: 行内弹性容器
  • 示例:
.container {
  display: flex;
}

4.1.2 flex-direction

  • **作用:**决定主轴的方向,即弹性子元素的排列方向。
  • 取值
    • row(默认值):主轴为水平方向,从左到右排列子元素。
    • row-reverse:主轴为水平方向,从右到左排列子元素。
    • column:主轴为垂直方向,从上到下排列子元素。
    • column-reverse:主轴为垂直方向,从下到上排列子元素。
  • 示例:
.flex-container {
    display: flex;
    flex-direction: column;
}
  • 效果:

4.1.3 flex-wrap

  • **作用:**控制弹性子元素在容器内是否换行。当子元素的总宽度超过容器宽度时,通过该属性决定如何处理。
  • 取值:
    • nowrap(默认值):不换行,子元素将在同一行内排列,可能会导致子元素被压缩。
    • wrap:换行,子元素在容器内自动换行,从新的一行开始排列。
    • wrap-reverse:换行,与wrap相反,从下往上换行排列。
  • 示例:
.flex-container {
    display: flex;
    flex-wrap: wrap;
    width: 300px;
}
.flex-item {
    width: 150px;
    height: 100px;
    background-color: lightblue;
    margin: 5px;
}
  • 效果:

4.1.4 flex-flow

  • 作用:flex-flow是flex-direction和flex-wrap的简写属性。
  • 取值:flex-flow: 。例如,flex-flow: row wrap表示主轴为水平方向,子元素在容器宽度不足时换行。
  • 示例:
.flex-container {
    display: flex;
    flex-flow: column wrap;
}

4.1.5 justify-content

  • **作用:**定义弹性子元素在主轴上的对齐方式。
  • 取值
    • flex-start(默认值):子元素在主轴起点对齐。
    • flex-end:子元素在主轴终点对齐。
    • center:子元素在主轴中心对齐。
    • space-between:子元素在主轴上均匀分布,两端对齐。
    • space-around:子元素在主轴上均匀分布,每个子元素两侧的空白空间相等。
    • space-evenly:子元素在主轴上均匀分布,每个子元素之间的间隔以及与容器两端的间隔都相等。
  • 示例:
.flex-container {
    display: flex;
    justify-content: space-between;
}
  • 效果:

4.1.6 align-items

  • 作用:定义弹性子元素在交叉轴上的对齐方式。
  • 取值
    • stretch(默认值):子元素在交叉轴方向上拉伸以填满容器。
    • flex-start:子元素在交叉轴起点对齐。
    • flex-end:子元素在交叉轴终点对齐。
    • center:子元素在交叉轴中心对齐。
    • baseline:子元素根据其基线对齐。
  • 示例:
.flex-container {
    display: flex;
    align-items: center;
    height: 300px;
}
.flex-item {
    height: 100px;
}
  • 效果:

4.1.7 align-content

  • **作用:**当弹性子元素有多行时,定义这些行在交叉轴上的对齐方式。如果只有一行子元素,该属性不起作用。
  • 取值**:**
    • stretch(默认值):子元素行在交叉轴上拉伸以填满容器。
    • flex-start:子元素行在交叉轴起点对齐。
    • flex-end:子元素行在交叉轴终点对齐。
    • center:子元素行在交叉轴中心对齐。
    • space-between:子元素行在交叉轴上均匀分布,两端对齐。
    • space-around:子元素行在交叉轴上均匀分布,每行两侧的空白空间相等。
  • 示例:
.flex-container {
    display: flex;
    flex-wrap: wrap;
    align-content: space - between;
    height: 400px;
}
.flex-item {
    width: 100px;
    height: 100px;
}
  • 效果:

4.1.8 justify-content、align-content、align-items的区别

  1. 作用对象不同
  • justify - content:主要用于控制弹性子元素在主轴上的对齐方式。这里的主轴方向由<font style="background-color:rgb(249, 250, 251);">flex - direction</font>属性决定,默认是水平方向(<font style="background-color:rgb(249, 250, 251);">row</font>)。简单来说,它影响的是所有弹性子元素在主轴上的分布情况。例如,在水平排列的导航栏中,使用<font style="background-color:rgb(249, 250, 251);">justify - content</font>可以让导航项在水平方向上均匀分布、居中对齐等。
  • align - content:该属性用于控制多行弹性子元素在交叉轴上的对齐方式。注意,它只有在弹性子元素出现换行(即<font style="background-color:rgb(249, 250, 251);">flex - wrap</font>属性值为<font style="background-color:rgb(249, 250, 251);">wrap</font><font style="background-color:rgb(249, 250, 251);">wrap - reverse</font>)时才起作用。例如,在一个有多行图片的画廊布局中,使用<font style="background-color:rgb(249, 250, 251);">align - content</font>可以调整图片行在垂直方向上的对齐方式。它决定的是多行子元素作为一个整体在交叉轴上如何分布和对齐。例如,在一个有多行文字段落的弹性容器中,<font style="background-color:rgb(249, 250, 251);">align - content</font>能控制这些段落行在垂直方向上的整体对齐表现 。
  • align - items:作用于弹性容器内的所有弹性子元素,控制每个子元素在交叉轴上的对齐方式。无论弹性子元素是否换行,该属性都对每个单独的子元素起作用。例如,在一个包含多个图片的弹性容器中,使用<font style="background-color:rgb(249, 250, 251);">align - items</font>可以统一设置这些图片在垂直方向(假设交叉轴为垂直方向)上的对齐方式。
  1. 取值及效果不同
  • justify - content:有<font style="background-color:rgb(249, 250, 251);">flex - start</font>(默认值,子元素在主轴起点对齐)、<font style="background-color:rgb(249, 250, 251);">flex - end</font>(子元素在主轴终点对齐)、<font style="background-color:rgb(249, 250, 251);">center</font>(子元素在主轴中心对齐)、<font style="background-color:rgb(249, 250, 251);">space - between</font>(子元素在主轴上均匀分布,两端对齐)、<font style="background-color:rgb(249, 250, 251);">space - around</font>(子元素在主轴上均匀分布,每个子元素两侧的空白空间相等)、<font style="background-color:rgb(249, 250, 251);">space - evenly</font>(子元素在主轴上均匀分布,每个子元素之间的间隔以及与容器两端的间隔都相等)这些取值。以<font style="background-color:rgb(249, 250, 251);">space - between</font>为例:效果是弹性子元素在水平方向上均匀分布,容器两端对齐。
.flex-container {
    display: flex;
    justify-content: space - between;
}
  • align - content:取值有<font style="background-color:rgb(249, 250, 251);">stretch</font>(默认值,子元素行在交叉轴上拉伸以填满容器)、<font style="background-color:rgb(249, 250, 251);">flex - start</font>(子元素行在交叉轴起点对齐)、<font style="background-color:rgb(249, 250, 251);">flex - end</font>(子元素行在交叉轴终点对齐)、<font style="background-color:rgb(249, 250, 251);">center</font>(子元素行在交叉轴中心对齐)、<font style="background-color:rgb(249, 250, 251);">space - between</font>(子元素行在交叉轴上均匀分布,两端对齐)、<font style="background-color:rgb(249, 250, 251);">space - around</font>(子元素行在交叉轴上均匀分布,每行两侧的空白空间相等) 。例如,当<font style="background-color:rgb(249, 250, 251);">align - content</font>取值为<font style="background-color:rgb(249, 250, 251);">space - around</font>时:效果是子元素行在交叉轴上均匀分布,并且每行两侧的空白空间相等。
.flex-container {
    display: flex;
    flex-wrap: wrap;
    align-content: space - around;
    height: 400px;
    border: 1px solid #ccc;
}
.flex-item {
    width: 100px;
    height: 100px;
    background-color: lightblue;
    margin: 5px;
}
  • align - items:取值有<font style="background-color:rgb(249, 250, 251);">stretch</font>(默认值,子元素在交叉轴方向上拉伸以填满容器)、<font style="background-color:rgb(249, 250, 251);">flex - start</font>(子元素在交叉轴起点对齐)、<font style="background-color:rgb(249, 250, 251);">flex - end</font>(子元素在交叉轴终点对齐)、<font style="background-color:rgb(249, 250, 251);">center</font>(子元素在交叉轴中心对齐)、<font style="background-color:rgb(249, 250, 251);">baseline</font>(子元素根据其基线对齐)。以<font style="background-color:rgb(249, 250, 251);">center</font>为例:无论弹性子元素的高度如何,它们都将在垂直方向上居中对齐。
.flex-container {
    display: flex;
    align-items: center;
    height: 300px;
}
.flex-item {
    height: 100px;
}

3. 应用场景不同

  • justify - content:适用于需要控制元素在水平或垂直方向(取决于主轴方向)上的分布情况。比如导航栏、水平排列的按钮组、产品展示的水平列表等场景。
  • align - content:适用于多行元素的布局场景,如多行文本段落的对齐、图片画廊中多行图片的排列、网格布局中多行元素的垂直分布等情况。在图片画廊布局中,有多行图片时,用<font style="background-color:rgb(249, 250, 251);">align - content</font>来控制图片行在垂直方向上的分布,如让它们均匀分布在容器内。
  • align - items:适用于需要对单个子元素在交叉轴上进行精细对齐控制的场景。如在一个水平排列的导航栏中,每个导航项的高度可能不一致,通过<font style="background-color:rgb(249, 250, 251);">align - items</font>可以确保它们在垂直方向上以特定方式对齐,比如都居中对齐。

5. 作用在flex子元素上的属性

  1. order
  • 作用:定义弹性子元素的排列顺序。数值越小,排列越靠前。
  • 取值:一个整数值,默认值为 0。
  • 示例
.flex-item1 {
    order: 2;
}
.flex-item2 {
    order: 1;
}
  1. flex-grow
  • 作用:定义弹性子元素的放大比例。当容器有剩余空间时,根据该属性值分配剩余空间。
  • 取值:一个非负数字,默认值为 0,表示不放大。如果所有子元素的flex-grow都为 0,即使容器有剩余空间,子元素也不会放大。
  • 示例
.flex-item1 {
    flex-grow: 1;
}
.flex-item2 {
    flex-grow: 2;
}
  • 效果:当容器有剩余空间时,flex - item2将比flex - item1分配到更多的空间,其宽度增长比例为 2:1。
  1. flex-shrink
  • 作用:定义弹性子元素的缩小比例。当容器空间不足时,根据该属性值决定子元素的缩小程度。
  • 取值:一个非负数字,默认值为 1,表示当空间不足时,子元素会缩小。如果所有子元素的flex-shrink都为 0,子元素不会缩小,可能会导致溢出。
  • 示例
.flex-item1 {
    flex-shrink: 0;
}
.flex-item2 {
    flex-shrink: 1;
}
  • 效果:当容器空间不足时,flex-item1不会缩小,而flex-item2会根据其flex-shrink值进行缩小。
  1. flex-basis
  • 作用:定义弹性子元素在分配多余空间之前的初始大小。可以设置为具体的长度值(如px、em等)或auto(默认值),auto表示根据子元素的内容自动计算大小。
  • 取值:一个长度值或auto。
  • 示例
.flex-item {
    flex-basis: 200px;
}
  • 效果:弹性子元素的初始宽度将被设置为 200px,然后再根据flex-grow和flex-shrink属性进行调整。
  1. flex
  • 作用:flex是flex-grow、flex-shrink和flex-basis的简写属性。
  • 取值:flex: 。例如,flex: 1 1 200px表示子元素的放大比例为 1,缩小比例为 1,初始宽度为 200px。常见的简写形式有flex: auto(等同于flex: 1 1 auto)和flex: none(等同于flex: 0 0 auto)。
  • 示例
.flex-item {
    flex: 1 0 150px;
}
  • 效果:子元素将在有剩余空间时放大,不会缩小,初始宽度为 150px。
  1. align-self
  • 作用:允许单个弹性子元素覆盖容器的align-items属性,单独定义自己在交叉轴上的对齐方式。
  • 取值:与align-items属性相同,包括stretch、flex-start、flex-end、center、baseline。
  • 示例
.flex-item {
    align-self: flex-end;
}
  • 效果:该弹性子元素将在交叉轴上与容器的终点对齐,而不受容器align-items属性的影响。

6. 使用举例

这里简单列举一下简单布局与自适应布局:

6.1 简单布局

<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
</div>
.container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.item {
  width: 100px;
  height: 100px;
  background-color: lightblue;
}

**效果:**三个方块在容器内水平排列,两边对齐,且在垂直方向居中。

6.2 自适应布局

<div class="container">
  <div class="item item1">Item 1</div>
  <div class="item item2">Item 2</div>
  <div class="item item3">Item 3</div>
</div>
.container {
  display: flex;
  flex-wrap: wrap;
}
.item {
  flex: 1 1 200px;/* flex-grow, flex-shrink, flex-basis */
  margin: 10px;
  min-width: 100px;
  background-color: lightgreen;
}
.item1 {
  order: 2;
}
.item2 {
  order: 1;
}
.item3 {
  order: 3;
}

**效果:**三个项目根据容器宽度自动换行排列,并且按照order属性重新排序,每个项目初始宽度为200px,最小宽度为100px,当空间不足时会缩小。

7. 使用中的注意事项

  1. 浏览器兼容性

需要考虑到不同浏览器对Flexbox的支持程度,在开发过程中可以通过Can I use等工具查询各个浏览器的支持情况,并添加必要的前缀(如-webkit-)以确保兼容性;或使用 JavaScript 库(如 Modernizr)进行检测,并提供备用的布局方案。

  1. 避免过度使用

虽然Flexbox功能强大,但并不是所有场景都适合使用它。例如,对于简单的表格布局或者只需要固定位置的元素,使用传统的布局方式可能更为简洁高效。

  1. 理解主轴和交叉轴的概念

这是正确使用Flexbox的关键,很多布局问题都是因为没有正确理解这两个概念导致的。

  1. 项目之间的间距

如果想要给项目之间添加间距,可以考虑使用margin属性,而不是直接修改justify-content或align-items,因为这可能会破坏整体布局逻辑。

  1. 避免过度嵌套

虽然 Flexbox 可以实现复杂的布局,但过度嵌套弹性容器可能会导致布局难以理解和维护。尽量保持布局结构的简洁。

  1. 注意属性的相互影响

Flexbox 的各个属性之间可能会相互影响。例如,flex-grow、flex-shrink和flex-basis属性共同决定了子元素的最终大小。在设置这些属性时,要充分考虑它们之间的关系,以达到预期的布局效果。

  1. 测试不同屏幕尺寸

由于 Flexbox 常用于响应式设计,在开发过程中要充分测试不同屏幕尺寸下的布局表现,确保在各种设备上都能呈现良好的效果。

8. 适用场景

  1. 导航栏布局:使用 Flexbox 可以轻松实现水平排列的导航菜单,并且能够方便地控制菜单项的对齐方式和间距。
  2. 卡片式布局:在展示多个卡片(如产品卡片、文章卡片)时,Flexbox 可以使卡片在容器内整齐排列,并且能够根据容器大小自动调整卡片的排列方式。
  3. 表单布局:对于表单元素的排列,Flexbox 可以实现标签和输入框的合理对齐,以及在不同屏幕尺寸下的自适应调整。
  4. 响应式网格布局:结合媒体查询,Flexbox 可以创建出灵活的响应式网格布局,在不同屏幕宽度下切换不同的列数和排列方式。

9. 示例代码仓库

gitee.com/anarkhao/cs…