对于CSS:弹性布局(Flexbox)的解析

开篇介绍:

hello 大家,本篇博客我们来学习CSS中的弹性布局。

大家好,欢迎来到这篇专为零基础同学打造的 CSS 弹性布局终极解析长文!如果你刚接触前端开发,一定被 CSS 布局折磨过无数次:

  • 想让一个登录框在页面正中间,试了margin:0 auto只能水平居中,垂直居中折腾了一下午,要么错位、要么缩放就崩;
  • 想让几个菜单在一行均匀分布,用inline-block写了,结果总有个莫名其妙的 4px 间隙,百度来的解决方法要么牺牲可读性、要么兼容性稀烂;
  • 做商品列表,想让卡片一行放 4 个、窗口缩小自动换行,用float写了,结果父元素高度直接塌陷,还要写一堆看不懂的clearfix代码;
  • 两个 div 上下排列,上面加了margin-bottom:30px,下面加了margin-top:20px,结果间距不是 50px 而是 30px,margin 合并的问题查了半天还是解决不了;
  • 想让几个高度不一样的盒子底部对齐,用传统布局试了定位、JS 算高度,一改内容就崩,完全不灵活。

我敢说,99% 的前端新手,都被这些传统布局的痛点逼到想砸键盘。而这些让你崩溃的问题,在CSS 弹性布局(Flexible Box,简称 Flexbox) 面前,只需要几行、甚至一行代码就能完美解决 ------ 它不用写复杂的 hack、不用算繁琐的百分比、不用处理莫名其妙的兼容性 bug,是现代前端开发绝对的主流布局方式,不管是 PC 端网页、移动端 H5 还是小程序,90% 的布局场景都能靠它轻松搞定。


一、弹性布局初体验:一行代码解决传统布局的所有痛点

我们先从原始代码入手,逐行逐字拆解,让你第一眼就看到弹性布局的威力 ------ 不用记复杂的属性,只需要加一行代码,就能解决传统布局里最让人崩溃的问题。

1.1 先看传统布局的 "翻车现场"

你给的这段代码,是所有新手刚学 CSS 都会写的,我们先把它完整写出来,看看传统布局下的效果有多让人崩溃:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>传统布局翻车现场</title>
  <style>
    /* 父元素div的样式 */
    div {
      width: 100%; /* 宽度占满整个浏览器窗口 */
      height: 150px; /* 固定高度150px */
      background-color: red; /* 红色背景,方便看父元素的范围 */
    }
    /* 父元素的直接子元素span的样式 */
    div>span {
      background-color: green; /* 绿色背景,方便看子元素的范围 */
      width: 100px; /* 给span设置宽度100px */
    }
  </style>
</head>
<body>
  <div>
    <span>1</span>
    <span>2</span>
    <span>3</span>
  </div>
</body>
</html>
新手的预期 vs 实际的翻车效果
  • 新手的预期 :我给 span 设置了width:100px,应该会出现 3 个 100px 宽的绿色方块,在红色的父元素里从左到右整齐排列,高度填满父元素的 150px;
  • 实际的效果 (你可以自己运行这段代码看看):
    1. 设置的 width 完全不生效:span 的宽度根本不是 100px,而是由里面的文字 "1"、"2"、"3" 的大小决定的,只有一点点宽,完全看不到 100px 的效果;
    2. 高度完全不对:span 的高度只有文字那么高,根本没有填满父元素的 150px,红色的父元素大部分都是空的;
    3. 有莫名其妙的空白间隙:三个 span 之间,有一个大概 4px 的空白间隙,哪怕你没设置任何 margin,这个间隙也存在;
    4. 完全无法控制排列:想让这三个 span 居中、靠右、均匀分布?用传统布局,你要写一堆代码,还不一定能完美实现。
为什么会翻车?底层原因彻底讲透

很多新手遇到这个问题,会以为是自己代码写错了,但其实不是 ------ 这是行内元素的固有特性,是传统布局的天生缺陷:

  1. span 是行内元素(inline) :行内元素的核心特性,就是width和height属性完全无效!行内元素的宽高,只能由里面的内容决定,你哪怕写width:1000px,浏览器也会直接忽略,根本不会生效;
  2. 行内元素无法填满父元素高度:行内元素的高度,永远由文字的行高决定,哪怕父元素有固定高度,行内元素也不会自动拉伸填满,这是传统布局的天生限制;
  3. 空白间隙是 HTML 换行导致的:HTML 代码里,三个 span 之间换了行,浏览器会把换行、空格解析成一个 "空白字符",这个空白字符有默认的宽度,所以就出现了 4px 左右的间隙,这是传统布局里最恶心的 bug 之一,没有完美的解决方法。

1.2 见证奇迹:加一行代码,所有问题全部解决!

现在,我们只需要给父元素的 CSS 里,加一行代码 :display: flex;,其他所有代码都不变,看看会发生什么翻天覆地的变化:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>弹性布局初体验</title>
  <style>
    div {
      width: 100%;
      height: 150px;
      background-color: red;
      /* 只加了这一行代码!其他所有代码都没变! */
      display: flex;
    }
    div>span {
      background-color: green;
      width: 100px;
    }
  </style>
</head>
<body>
  <div>
    <span>1</span>
    <span>2</span>
    <span>3</span>
  </div>
</body>
</html>
运行之后的神奇效果

你运行这段代码会发现,之前所有的翻车问题,全部解决了!

  1. width 属性生效了! 三个 span 现在都是标准的 100px 宽,和你设置的完全一致,浏览器再也不会忽略了;
  2. 高度自动填满父元素了! 三个 span 的高度,自动填充满了父元素的 150px 高度,整个红色的父元素被绿色的 span 填满了,再也没有空的区域;
  3. 莫名其妙的空白间隙消失了! 三个 span 之间干干净净,没有任何多余的间隙,完全贴合你设置的样式;
  4. 三个 span 自动在一行整齐排列了! 从左到右依次排开,不会换行,也不会错位;
  5. 后续的排列控制变得无比简单! 想让它们居中?再加一行justify-content: center;就搞定;想让它们靠右?justify-content: flex-end;;想让它们均匀分布?justify-content: space-around;,一行代码搞定,不用写任何复杂的逻辑。
为什么加了一行 display:flex,就有这么大的变化?

我们先不讲复杂的概念,用大白话告诉你浏览器做了什么:当你给父元素设置display: flex;的时候,浏览器会立刻把这个父元素变成一个弹性容器(Flex Container),同时,这个父元素的所有直接子元素,会自动变成弹性项目(Flex Item)。

  • 一旦子元素变成了弹性项目,它就会自动失去行内元素、块级元素的传统限制:行内元素可以设置宽高了、块级元素不会独占一行了、空白间隙消失了;
  • 弹性容器会全权控制里面所有弹性项目的排列方式、大小、位置,你只需要给容器加几个简单的属性,就能实现任何你想要的布局效果,不用再关心传统布局的那些恶心 bug。

这就是弹性布局的魅力 ------ 它把传统布局里需要几十行代码、还要处理各种 bug 的需求,简化成了几行、甚至一行代码,而且逻辑清晰、兼容性拉满,所有现代浏览器都完美支持。


二、弹性布局的核心基本概念:搞不懂这些,背再多属性也没用

很多新手学弹性布局,一上来就背justify-content的取值,结果一写就错,核心原因就是没有搞懂弹性布局的几个基础概念。这些概念是弹性布局的地基,你只有把地基打牢了,后面的属性才能学明白,遇到问题也能快速定位原因。

2.1 两个核心角色:弹性容器(Flex Container)和弹性项目(Flex Item)

弹性布局里,只有两个核心角色,所有的属性、所有的效果,都是围绕这两个角色展开的,你必须先把它们的定义、范围、特性彻底搞懂。

2.1.1 弹性容器(Flex Container):布局的 "老大"
  • 官方定义 :任何一个 HTML 元素,只要你给它设置了display: flex;(或者display: inline-flex;,后面会讲),它就立刻变成了一个弹性容器;
  • 大白话解释:弹性容器就是布局的 "老大",它负责制定规则,控制里面所有 "小弟"(子元素)的排列方式、位置、大小、间距,所有的布局规则,都是给这个 "老大" 设置的;
  • 你必须知道的细节 :
    1. 任何元素都能变成弹性容器 :不管是块级元素div、p、ul,还是行内元素span、a,甚至是body、html标签,只要设置了display: flex;,就能变成弹性容器,没有任何限制;

    2. 行内元素变成弹性容器后,会发生什么? 行内元素默认是不能设置宽高的,设置了display: flex;之后,它会变成一个 "块级的弹性容器",默认宽度占满父元素,可以设置宽高,和块级元素的表现一致;如果你想让它保持行内元素的特性,不独占一行,可以设置display: inline-flex;,但新手阶段几乎用不到,了解即可;

    3. 弹性容器的控制范围,只到直接子元素 :这是新手最容易踩的坑!弹性容器只能控制它的直接子元素 ,孙子元素(子元素的子元素)完全不受影响!举个例子,看这段 HTML 结构:

      复制代码
      <div class="parent"> <!-- 给这个div设置了display:flex,它是弹性容器 -->
        <div class="child1"> <!-- 直接子元素,是弹性项目,受parent的flex属性控制 -->
          <div class="grandson">我是孙子元素</div> <!-- 不是直接子元素,不是弹性项目,不受parent的flex属性控制 -->
        </div>
        <div class="child2"> <!-- 直接子元素,是弹性项目 -->
          <p>我也是孙子元素</p> <!-- 不受parent的flex属性控制 -->
        </div>
      </div>

      很多新手会问:我给 parent 设置了display:flex;,为什么 grandson 这个元素没有排列?因为它不是直接子元素,弹性容器管不到它!如果你想控制 grandson 的排列,必须给它的父元素 child1 也设置display:flex;,让 child1 也变成弹性容器,才能控制 grandson;

    4. 伪元素也会被当成弹性项目 :给弹性容器设置的::before、::after伪元素,会被浏览器当成直接子元素,也就是弹性项目,会参与弹性布局的排列。比如你想给导航栏加一个分隔线,用伪元素实现,它会和其他菜单项一起排列,非常方便;

    5. 弹性容器的默认样式变化 :设置了display:flex;之后,容器的overflow默认是visible,和普通块级元素一致;如果容器没有设置高度,默认会被弹性项目的高度撑开,不会出现高度塌陷的问题,这也是弹性布局比 float 布局好太多的原因之一。

2.1.2 弹性项目(Flex Item):布局的 "小弟"
  • 官方定义 :弹性容器的所有直接子元素 ,会自动变成该容器的弹性项目,不需要你做任何额外的设置;
  • 大白话解释:弹性项目就是布局的 "小弟",它们会听弹性容器(老大)制定的规则,按照规则排列,同时你也可以给单个 "小弟" 设置单独的规则,让它和其他 "小弟" 不一样;
  • 你必须知道的细节 :
    1. 弹性项目会自动失去传统布局的部分特性 :这是弹性布局的核心,也是新手最容易懵的地方:
      • 行内元素变成弹性项目后,会自动拥有块级元素的特性:可以设置width、height、margin、padding,所有方向都生效,再也不会出现行内元素宽高不生效的问题了;
      • 块级元素变成弹性项目后,不会再独占一行了,会默认和其他弹性项目排在一行,哪怕你给它设置了宽度,也不会换行;
      • 弹性项目的float、clear、vertical-align属性会完全失效 !很多从传统布局转过来的新手,习惯给元素加float:left;,结果发现在弹性布局里完全没用,就是这个原因 ------ 弹性布局有自己的排列规则,根本不需要浮动,浏览器会直接忽略这几个属性;
    2. 弹性项目的默认尺寸规则 :如果弹性项目没有设置width,默认宽度由内容决定;如果没有设置height,默认高度会拉伸填满弹性容器的高度(这就是我们初体验里,span 自动填满父元素高度的原因);
    3. 绝对定位的子元素,不是弹性项目 :如果给直接子元素设置了position: absolute;或者position: fixed;,它就会脱离文档流,不再是弹性项目,不受弹性容器的 flex 属性控制,浏览器会忽略它的排列;
    4. 弹性项目的 margin 不会发生垂直合并:传统布局里,两个块级元素的上下 margin 会合并,而弹性项目的 margin,不管是水平还是垂直,都不会合并,你设置多少就是多少,再也不用处理 margin 塌陷的问题了!

2.2 两个核心方向:主轴(Main Axis)和侧轴(Cross Axis)

这是弹性布局里最重要、也是最容易让新手搞混的概念!我们后面要讲的所有核心属性,比如justify-content、align-items,都是围绕这两个轴展开的 ------ 你搞不清哪个是主轴、哪个是侧轴,这两个属性就一定会用反,写了也不生效!

2.2.1 先搞懂:什么是 "轴"?

用大白话讲,"轴" 就是方向,就像我们数学里的 x 轴(水平方向)和 y 轴(垂直方向),它规定了元素排列的 "路线"。弹性布局里有两个互相垂直的轴,就像一个十字,一个管主排列方向,一个管副排列方向。

2.2.2 主轴(Main Axis):弹性项目排列的 "主路线"
  • 官方定义 :主轴是弹性项目默认排列的核心方向,所有弹性项目,都会默认沿着主轴的方向,从主轴的起点,往主轴的终点,一个接一个地排列;
  • 大白话解释:你可以把主轴想象成教室里的 "排队路线"------ 你让同学们从左到右排成一行,那 "从左到右的水平方向" 就是主轴;你让同学们从上到下排成一列,那 "从上到下的垂直方向" 就是主轴。主轴,就是你让项目排队的主方向;
  • 你必须知道的核心细节 :
    1. 主轴有起点和终点:主轴不是一条无限长的线,它的起点就是弹性容器的对应边缘,终点就是弹性容器的另一边缘。比如主轴是水平从左到右,那主轴起点就是容器的最左侧,主轴终点就是容器的最右侧;
    2. 主轴的方向是可以改变的 :这是弹性布局最灵活的地方!主轴的方向不是固定的,我们可以通过flex-direction属性,随时改变主轴的方向,主轴变了,整个布局的排列逻辑都会跟着变;
    3. 默认的主轴方向 :如果你不做任何设置,主轴的默认方向是水平方向,从左到右------ 也就是弹性项目默认从容器的最左边开始,往最右边排列,一个接一个在一行显示,就像我们初体验里的效果一样。
2.2.3 侧轴(Cross Axis):和主轴垂直的 "副路线"
  • 官方定义 :侧轴是永远和主轴垂直的那个方向,主轴是水平的,侧轴就是垂直的;主轴是垂直的,侧轴就是水平的,没有例外;
  • 大白话解释:还是用教室排队的例子,你让同学们从左到右排成一行(主轴水平),那和这个方向垂直的,就是 "从上到下的垂直方向",这就是侧轴;你让同学们从上到下排成一列(主轴垂直),那和这个方向垂直的,就是 "从左到右的水平方向",这就是侧轴。侧轴,就是和主排队方向垂直的那个副方向;
  • 你必须知道的核心细节 :
    1. 侧轴也有起点和终点:比如主轴是水平从左到右,侧轴就是垂直从上到下,侧轴起点就是容器的最顶部,侧轴终点就是容器的最底部;
    2. 侧轴永远跟着主轴变:主轴的方向改变,侧轴的方向一定会跟着改变,因为它永远和主轴垂直,这一点一定要记死!
    3. 默认的侧轴方向 :因为默认主轴是水平从左到右,所以默认的侧轴方向是垂直方向,从上到下。
2.2.4 一张表 + 一个例子,彻底搞懂主轴和侧轴的对应关系

很多新手记不住主轴变了之后侧轴怎么变,我给你整理了一张表,把flex-direction的四个取值(后面会详细讲)对应的主轴、侧轴方向,全部列出来,一目了然:

flex-direction 取值 主轴方向 主轴起点 主轴终点 侧轴方向 侧轴起点 侧轴终点
row(默认值) 水平方向 容器左侧 容器右侧 垂直方向 容器顶部 容器底部
row-reverse 水平方向 容器右侧 容器左侧 垂直方向 容器顶部 容器底部
column 垂直方向 容器顶部 容器底部 水平方向 容器左侧 容器右侧
column-reverse 垂直方向 容器底部 容器顶部 水平方向 容器左侧 容器右侧

我们再用一个最直观的例子,帮你彻底理解:

  • 当flex-direction: row;(默认):
    • 主轴是水平从左到右,所以justify-content(控制主轴排列)管的是水平方向 的排列,align-items(控制侧轴排列)管的是垂直方向的排列;
  • 当flex-direction: column;:
    • 主轴变成了垂直从上到下,所以justify-content管的是垂直方向 的排列,align-items管的是水平方向的排列!

很多新手在这里踩坑:想让项目垂直居中,主轴是 column 的时候,写了align-items: center;,结果只水平居中了,垂直没反应,就是因为搞反了主轴和侧轴!记住:justify-content永远管主轴,align-items永远管侧轴,主轴变了,它们管的方向就变了!


三、弹性容器的核心属性:从入门到精通,每一个都拆到极致

搞懂了基本概念,我们现在开始讲弹性布局的核心属性。弹性布局的属性分为两大类:

  1. 设置在弹性容器上的属性:给父元素设置,控制所有弹性项目的整体排列规则,是弹性布局的核心,我们先讲这部分;
  2. 设置在弹性项目上的属性:给子元素设置,控制单个项目的特殊规则,我们讲完容器属性之后,会把这部分也拆到极致。

justify-content、align-items、flex-wrap,都是设置在弹性容器上的属性、

3.1 flex-direction:决定主轴的方向!(容器属性)

这个属性是弹性布局的 "总开关",它决定了主轴的方向,也就决定了所有弹性项目的主排列方向,是所有属性的基础,我们第一个讲。

3.1.1 四个常用取值,每一个都讲透

flex-direction一共有四个常用取值,对应四个不同的主轴方向,我们一个一个地拆解,每一个都配代码示例、效果描述、适用场景,让你彻底搞懂。

取值 1:row(默认值,水平从左到右)
  • 含义 :主轴为水平方向 ,起点在弹性容器的左侧 ,终点在容器的右侧,弹性项目从左到右,依次排列在一行;

  • 大白话解释:就像我们平时看书,从左到右一行一行看,项目会从容器的最左边开始,一个接一个往右排,默认不会换行;

  • 侧轴对应方向:垂直方向,从上到下;

  • 适用场景:这是默认值,不用特意写,适合绝大多数横向排列的布局,比如导航栏、按钮组、商品卡片列表等,是我们用得最多的取值;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      flex-direction: row; /* 默认值,可以不写 */
    }
取值 2:row-reverse(水平从右到左,反向排列)
  • 含义 :主轴还是水平方向 ,但起点和终点反过来了 ------ 起点在容器的右侧 ,终点在容器的左侧,弹性项目从右到左,依次排列在一行;

  • 大白话解释:和 row 的排列顺序完全反过来,第一个项目在最右边,最后一个项目在最左边,就像把 row 的排列结果水平翻转了一样;

  • 侧轴对应方向:垂直方向,从上到下;

  • 适用场景:需要把项目反向排列的场景,比如导航栏的菜单需要靠右排列,同时顺序反过来,或者一些特殊的排版需求;

  • 代码示例 + 效果对比 :

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>row vs row-reverse对比</title>
      <style>
        .container {
          width: 500px;
          height: 100px;
          background-color: #f0f0f0;
          display: flex;
          margin: 20px;
        }
        .row {
          flex-direction: row; /* 默认从左到右 */
        }
        .row-reverse {
          flex-direction: row-reverse; /* 从右到左反向 */
        }
        .item {
          width: 80px;
          height: 80px;
          background-color: #007AFF;
          color: white;
          font-size: 24px;
          /* 让文字居中 */
          display: flex;
          justify-content: center;
          align-items: center;
          margin: 5px;
        }
      </style>
    </head>
    <body>
      <h3>flex-direction: row;(默认,从左到右)</h3>
      <div class="container row">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    
      <h3>flex-direction: row-reverse;(从右到左反向)</h3>
      <div class="container row-reverse">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    </body>
    </html>

    运行这段代码,你会直观地看到:row 模式下,1、2、3 从左到右排;row-reverse 模式下,3、2、1 从右到左排,顺序完全反过来了。

取值 3:column(垂直从上到下)
  • 含义 :主轴变成垂直方向 ,起点在弹性容器的顶部 ,终点在容器的底部,弹性项目从上到下,依次排列在一列;

  • 大白话解释:就像我们写作文,从上到下一段一段写,项目会从容器的最顶部开始,一个接一个往下排,默认不会换列;

  • 侧轴对应方向:水平方向,从左到右;

  • 重点提醒 :主轴变成垂直之后,justify-content就变成了控制垂直方向 的排列,align-items变成了控制水平方向的排列,千万不要搞反!

  • 适用场景:需要纵向排列的布局,比如移动端的页面布局、侧边栏的菜单、表单的输入项列表等;

  • 代码示例 + 效果对比 :

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>row vs column对比</title>
      <style>
        .container {
          width: 500px;
          height: 300px;
          background-color: #f0f0f0;
          display: flex;
          margin: 20px;
          border: 2px solid #333;
        }
        .row {
          flex-direction: row; /* 水平主轴 */
        }
        .column {
          flex-direction: column; /* 垂直主轴 */
        }
        .item {
          width: 80px;
          height: 80px;
          background-color: #007AFF;
          color: white;
          font-size: 24px;
          display: flex;
          justify-content: center;
          align-items: center;
          margin: 5px;
        }
      </style>
    </head>
    <body>
      <h3>flex-direction: row;(主轴水平,项目横向排列)</h3>
      <div class="container row">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    
      <h3>flex-direction: column;(主轴垂直,项目纵向排列)</h3>
      <div class="container column">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    </body>
    </html>

    运行这段代码,你会直观地看到:row 模式下项目横向排一行,column 模式下项目纵向排一列,完全不一样。

取值 4:column-reverse(垂直从下到上,反向排列)
  • 含义 :主轴还是垂直方向 ,但起点和终点反过来了 ------ 起点在容器的底部 ,终点在容器的顶部,弹性项目从下到上,依次排列在一列;

  • 大白话解释:和 column 的排列顺序完全反过来,第一个项目在最下面,最后一个项目在最上面,就像把 column 的排列结果垂直翻转了一样;

  • 侧轴对应方向:水平方向,从左到右;

  • 适用场景:需要反向纵向排列的特殊场景,比如聊天记录的消息列表,最新的消息在最下面;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      flex-direction: column-reverse;
    }
3.1.2 避坑指南
  1. 坑 1:主轴变了,justify-content 和 align-items 的控制方向也变了,还按原来的写,结果不生效
    • 解决方法:每次用这两个属性之前,先看一眼flex-direction是什么,确定好主轴和侧轴的方向,再写对应的属性;
  2. 坑 2:用了 row-reverse,以为只是排列顺序反了,结果 justify-content:flex-start 也贴到右边了
    • 原因:row-reverse 不仅改变了项目的排列顺序,还改变了主轴的起点和终点,flex-start 是紧贴主轴起点,所以就贴到右边了;
    • 解决方法:如果只是想改变项目的渲染顺序,不想改变主轴的起点,不要用 row-reverse,用弹性项目的order属性(后面会讲);
  3. 坑 3:给弹性容器设置了 flex-direction:column,项目的 width:100% 不生效
    • 原因:弹性项目在 column 模式下,默认宽度会自动填满弹性容器的宽度,和 width:100% 的效果一样,哪怕你不写,也会自动填满;
    • 解决方法:column 模式下,不用给项目写 width:100%,默认就会填满容器宽度。

3.2 justify-content:控制主轴上的项目排列!(容器属性)

这个属性是弹性布局里最常用的属性之一,它的作用是:控制所有弹性项目,在主轴方向上的排列方式、以及剩余空间的分配方式。

这里有一个核心关键词:剩余空间 。很多新手搞不懂justify-content的各个取值的区别,就是因为没搞懂什么是剩余空间,以及浏览器是怎么分配剩余空间的。我们先把这个核心概念讲透,再讲每一个取值,你会发现所有的取值都变得无比简单。

3.2.1 先搞懂核心:什么是剩余空间?

剩余空间,就是弹性容器在主轴方向上的总尺寸,减去所有弹性项目在主轴方向上的总尺寸(包括项目的 margin、border、padding),剩下的空白空间。

我们用最具体的数字:

  • 例子前提:主轴是水平方向(flex-direction:row),弹性容器的宽度是 500px;
  • 容器里有 3 个弹性项目,每个项目的宽度是 100px,每个项目的左右 margin 各 5px;
  • 单个项目在主轴方向上占据的总尺寸 = 宽度 + 左 margin + 右 margin = 100 + 5 + 5 = 110px;
  • 3 个项目的总尺寸 = 110 * 3 = 330px;
  • 剩余空间 = 容器主轴尺寸 - 项目总尺寸 = 500 - 330 = 170px;

这个 170px,就是我们要分配的剩余空间,justify-content的所有取值,本质上就是用不同的规则,来分配这 170px 的剩余空间!

如果项目的总尺寸,大于等于容器的主轴尺寸,那就没有剩余空间了,这时候justify-content的大部分取值都不会有明显效果,因为没有空间可以分配了,这也是很多新手写了justify-content没效果的核心原因之一!

3.2.2 六个常用取值,每一个都讲透分配逻辑

justify-content一共有六个常用取值,我们按照使用频率排序,一个一个地拆解

取值 1:flex-start(默认值,紧贴主轴起点)
  • 分配逻辑 :所有的剩余空间,全部放在主轴终点的一侧 ,弹性项目全部紧贴着主轴起点排列;

  • 用上面的数字例子计算:170px 的剩余空间,全部放在容器的最右侧(主轴终点),项目紧贴着最左侧(主轴起点)排列,项目之间没有额外的间距;

  • 默认主轴(row)下的效果:项目全部贴在容器的最左边,右边有一大片空白;

  • 适用场景:默认的排列方式,不需要特意写,适合大多数从左到右的横向排列,比如导航栏的菜单、按钮组;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      justify-content: flex-start; /* 默认值,可以不写 */
    }
取值 2:flex-end(紧贴主轴终点)
  • 分配逻辑 :所有的剩余空间,全部放在主轴起点的一侧 ,弹性项目全部紧贴着主轴终点排列;

  • 用上面的数字例子计算:170px 的剩余空间,全部放在容器的最左侧(主轴起点),项目紧贴着最右侧(主轴终点)排列,项目之间没有额外的间距;

  • 默认主轴(row)下的效果:项目全部贴在容器的最右边,左边有一大片空白;

  • 适用场景:需要把项目放在容器右侧的场景,比如导航栏的用户信息、购物车按钮、表单的提交按钮;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      justify-content: flex-end;
    }
取值 3:center(在主轴上居中排列)
  • 分配逻辑 :剩余空间平均分成两份,一份放在主轴起点的一侧 ,一份放在主轴终点的一侧,弹性项目在主轴的正中间排列;

  • 用上面的数字例子计算:170px 的剩余空间,分成两份,每份 85px,左边放 85px,右边放 85px,项目在容器的正中间,项目之间没有额外的间距;

  • 默认主轴(row)下的效果:项目全部在容器的水平正中间,左右两边的空白一样大;

  • 适用场景:需要让项目水平居中的场景,比如页面的标题、登录框、居中的按钮组,是我们用得非常多的取值;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      justify-content: center;
    }
取值 4:space-around(环绕空白,每个项目左右空白相等)
  • 分配逻辑 :剩余空间平均分配给每一个弹性项目的左右两侧,每个项目的左边有一份空白,右边也有一份空白,所有空白的大小完全相等;

  • 用上面的数字例子计算 :3 个项目,每个项目左右各有一份空白,总共有 3*2=6 份空白,每份空白的大小 = 170px / 6 ≈ 28.33px;

    • 第一个项目的左边:28.33px;
    • 第一个和第二个项目之间:28.33 + 28.33 = 56.66px(第一个的右边 + 第二个的左边);
    • 第二个和第三个项目之间:同样 56.66px;
    • 第三个项目的右边:28.33px;
  • 默认主轴(row)下的效果:项目均匀分布,两端的空白是项目之间空白的一半;

  • 适用场景:需要项目均匀分布,且两端也有留白的场景,比如功能图标列表、商品卡片的横向排列、底部导航栏;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      justify-content: space-around;
    }
取值 5:space-between(两端对齐,中间空白相等)
  • 分配逻辑 :第一个弹性项目紧贴主轴起点,最后一个弹性项目紧贴主轴终点 ,剩余的空间平均分配给项目和项目之间的间隙;

  • 用上面的数字例子计算 :3 个项目,有 2 个中间间隙,每份间隙的大小 = 170px / 2 = 85px;

    • 第一个项目贴最左边,最后一个贴最右边;
    • 第一个和第二个项目之间:85px;
    • 第二个和第三个项目之间:85px;
  • 默认主轴(row)下的效果:项目两端贴边,中间的间距完全相等,均匀分布;

  • 适用场景:需要两端对齐、中间均匀分布的场景,比如导航栏(左边 logo、中间菜单、右边用户信息)、表单的按钮组(左边取消、右边确定)、商品列表的两端对齐排列,是我们用得非常多的取值;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      justify-content: space-between;
    }
取值 6:space-evenly(均匀空白,所有空白完全相等)
  • 分配逻辑 :剩余空间平均分配给所有的间隙,包括主轴起点和第一个项目之间、项目和项目之间、最后一个项目和主轴终点之间,所有的间隙大小完全相等;

  • 用上面的数字例子计算 :3 个项目,有 4 个间隙(左、2 个中间、右),每份间隙的大小 = 170px / 4 = 42.5px;

    • 第一个项目的左边:42.5px;
    • 项目之间的间隙:42.5px;
    • 最后一个项目的右边:42.5px;
    • 所有的空白完全一样大;
  • 默认主轴(row)下的效果:项目均匀分布,两端的空白和项目之间的空白完全相等;

  • 适用场景:需要所有空白完全均匀的场景,比如页面的功能入口、图标导航;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      justify-content: space-evenly;
    }
3.2.3 代码示例:六个取值的直观效果对比

我们把这六个取值放在同一个代码示例里,你运行之后就能直观地看到它们的区别,彻底搞懂剩余空间的分配逻辑:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>justify-content六个取值对比</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .demo {
      margin: 20px;
      padding: 10px;
      border: 2px solid #333;
    }
    .container {
      width: 500px;
      height: 100px;
      background-color: #f0f0f0;
      display: flex;
      flex-direction: row; /* 固定主轴为水平,方便对比 */
      margin-top: 10px;
    }
    .item {
      width: 100px;
      height: 80px;
      background-color: #007AFF;
      color: white;
      font-size: 24px;
      display: flex;
      justify-content: center;
      align-items: center;
      margin: 0 5px; /* 左右margin5px,和我们的计算例子一致 */
    }
    /* 六个不同的取值 */
    .flex-start { justify-content: flex-start; }
    .flex-end { justify-content: flex-end; }
    .center { justify-content: center; }
    .space-around { justify-content: space-around; }
    .space-between { justify-content: space-between; }
    .space-evenly { justify-content: space-evenly; }
  </style>
</head>
<body>
  <div class="demo">
    <h3>justify-content: flex-start;(默认,紧贴左侧)</h3>
    <div class="container flex-start">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
  </div>

  <div class="demo">
    <h3>justify-content: flex-end;(紧贴右侧)</h3>
    <div class="container flex-end">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
  </div>

  <div class="demo">
    <h3>justify-content: center;(水平居中)</h3>
    <div class="container center">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
  </div>

  <div class="demo">
    <h3>justify-content: space-around;(每个项目左右空白相等)</h3>
    <div class="container space-around">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
  </div>

  <div class="demo">
    <h3>justify-content: space-between;(两端对齐,中间空白相等)</h3>
    <div class="container space-between">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
  </div>

  <div class="demo">
    <h3>justify-content: space-evenly;(所有空白完全相等)</h3>
    <div class="container space-evenly">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
  </div>
</body>
</html>

运行这段代码,你会直观地看到六个取值的区别,尤其是space-around、space-between、space-evenly的细微差别,一眼就能看明白。

3.2.4 避坑指南
  1. 坑 1:写了 justify-content,但是没有任何效果
    • 90% 的原因:没有剩余空间!项目的总尺寸已经等于或者超过了容器的主轴尺寸,没有空白空间可以分配,所以写了也白写;
    • 解决方法:给容器设置足够的主轴尺寸,或者减少项目的总尺寸,确保有剩余空间;
  2. 坑 2:主轴是 column,写了 justify-content:center,项目没有水平居中,反而垂直居中了
    • 原因:主轴是垂直方向,justify-content 管的是主轴(垂直)的排列,所以只会垂直居中;
    • 解决方法:主轴是 column 的时候,水平居中要用align-items: center;,因为侧轴是水平方向;
  3. 坑 3:用了 space-between,最后一行的项目数量不够,排列乱了
    • 原因:space-between 是 "两端对齐",如果最后一行只有 1-2 个项目,会出现一个贴最左、一个贴最右,中间一大片空白的情况,非常丑;
    • 解决方法:给容器加几个空的弹性项目,宽度和正常项目一样,没有内容,把最后一行的位置填满,或者用 grid 布局(更适合多行多列的列表);
  4. 坑 4:项目设置了 margin,影响了剩余空间的计算
    • 原因:剩余空间的计算,是包含项目的 margin 的,很多新手只算了项目的 width,没算 margin,导致剩余空间和预期的不一样;
    • 解决方法:计算剩余空间的时候,一定要把项目的 margin、border、padding 都算进去。

3.3 align-items:控制侧轴上的单行项目排列!(容器属性)

讲完了主轴的排列,我们来讲侧轴的排列。align-items的作用是:控制所有弹性项目,在侧轴方向上的排列方式,注意:它是针对单行的弹性项目生效的,如果项目换行了(有多行),就要用align-content属性,这个我们后面会讲。

和justify-content不一样,align-items不涉及剩余空间的复杂分配,它的核心是控制项目在侧轴上的对齐方式,逻辑更简单,我们先讲默认的侧轴方向(主轴 row,侧轴垂直从上到下),再讲主轴变化后的情况。

3.3.1 五个常用取值,每一个都讲透

align-items一共有五个常用取值,我们按照使用频率排序,一个一个地拆解,重点讲你给的资料里提到的stretch(默认值)和center(垂直居中)。

取值 1:stretch(拉伸,默认值!)
  • 含义 :如果弹性项目没有显式设置侧轴方向的尺寸 (主轴是 row 的时候,就是 height),那么项目的侧轴尺寸会自动拉伸填充满整个弹性容器的侧轴尺寸;

  • 大白话解释:这就是我们初体验里,span 自动填满父元素高度的原因!默认情况下,只要你没给项目设置 height,项目的高度会自动拉伸到和容器一样高,填满整个容器;

  • 核心前提 :必须是项目没有显式设置侧轴方向的尺寸(或者设置为 auto),如果项目已经设置了固定的 height(主轴 row 时),stretch 就不会生效,浏览器会优先使用你设置的固定尺寸;

  • 默认侧轴(垂直)下的效果:没设置 height 的项目,高度自动填满容器的高度;设置了 height 的项目,保持你设置的高度,顶部对齐;

  • 适用场景:默认值,不用特意写,适合让项目的高度和容器一致的场景,比如导航栏的菜单项、卡片列表的卡片、表单的输入框和按钮对齐;

  • 代码示例 :

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>align-items: stretch; 拉伸效果</title>
      <style>
        .container {
          width: 500px;
          height: 200px; /* 容器高度200px */
          background-color: #f0f0f0;
          display: flex;
          align-items: stretch; /* 默认值,可以不写 */
          justify-content: space-around;
        }
        /* 项目1:没有设置height,会拉伸 */
        .item-no-height {
          width: 100px;
          background-color: #007AFF;
          color: white;
          display: flex;
          justify-content: center;
          align-items: center;
        }
        /* 项目2:设置了height:100px,不会拉伸 */
        .item-with-height {
          width: 100px;
          height: 100px; /* 显式设置了height */
          background-color: #FF9500;
          color: white;
          display: flex;
          justify-content: center;
          align-items: center;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <div class="item-no-height">无height,自动拉伸</div>
        <div class="item-with-height">有height,不拉伸</div>
        <div class="item-no-height">无height,自动拉伸</div>
      </div>
    </body>
    </html>

    运行这段代码,你会直观地看到:没有设置 height 的蓝色项目,高度自动填满了容器的 200px 高度;设置了 height 的橙色项目,保持 100px 的高度,没有拉伸,完美验证了我们讲的规则。

取值 2:flex-start(紧贴侧轴起点)
  • 含义 :所有弹性项目,都紧贴着侧轴的起点排列;

  • 默认侧轴(垂直)下的效果:侧轴起点是容器的顶部,所以项目全部贴在容器的最顶部,底部可能会有剩余空间;

  • 适用场景:需要项目顶部对齐的场景,比如卡片列表里的内容,顶部对齐;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      align-items: flex-start;
    }
取值 3:flex-end(紧贴侧轴终点)
  • 含义 :所有弹性项目,都紧贴着侧轴的终点排列;

  • 默认侧轴(垂直)下的效果:侧轴终点是容器的底部,所以项目全部贴在容器的最底部,顶部可能会有剩余空间;

  • 适用场景:需要项目底部对齐的场景,比如卡片的按钮,永远贴在卡片的底部;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      align-items: flex-end;
    }
取值 4:center(在侧轴上居中排列!重点中的重点!)
  • 含义 :所有弹性项目,都在侧轴的正中间排列,侧轴起点和终点的剩余空间完全相等;

  • 默认侧轴(垂直)下的效果 :项目在容器的垂直正中间排列!这就是弹性布局最经典的 "垂直居中" 实现方式!

  • 重点中的重点 :配合justify-content: center;,就能实现水平垂直都居中!三行代码搞定传统布局里折腾一下午都实现不了的效果,这是弹性布局最常用的场景!

  • 适用场景:垂直居中、水平垂直居中,比如登录框、弹窗、按钮里的文字、图标和文字的对齐,是我们用得最多的取值;

  • 经典代码示例(水平垂直居中) :

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>弹性布局经典:水平垂直居中</title>
      <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
        /* 父容器:占满整个视口高度 */
        body {
          width: 100%;
          min-height: 100vh; /* 最小高度等于浏览器视口的高度 */
          /* 核心三行代码,实现子元素水平垂直居中 */
          display: flex;
          justify-content: center; /* 主轴(水平)居中 */
          align-items: center; /* 侧轴(垂直)居中 */
          background-color: #f5f5f5;
        }
        /* 子元素:要居中的登录框 */
        .login-box {
          width: 350px;
          padding: 30px;
          background-color: white;
          border-radius: 8px;
          box-shadow: 0 2px 12px rgba(0,0,0,0.1);
        }
        .login-box h2 {
          text-align: center;
          margin-bottom: 20px;
          color: #333;
        }
        .form-item {
          margin-bottom: 15px;
        }
        .form-item label {
          display: block;
          margin-bottom: 5px;
          color: #666;
        }
        .form-item input {
          width: 100%;
          height: 40px;
          padding: 0 10px;
          border: 1px solid #ddd;
          border-radius: 4px;
        }
        .login-btn {
          width: 100%;
          height: 44px;
          background-color: #007AFF;
          color: white;
          border: none;
          border-radius: 4px;
          font-size: 16px;
          cursor: pointer;
          margin-top: 10px;
        }
      </style>
    </head>
    <body>
      <div class="login-box">
        <h2>用户登录</h2>
        <div class="form-item">
          <label>用户名</label>
          <input type="text" placeholder="请输入用户名">
        </div>
        <div class="form-item">
          <label>密码</label>
          <input type="password" placeholder="请输入密码">
        </div>
        <button class="login-btn">登录</button>
      </div>
    </body>
    </html>

    运行这段代码,你会看到:白色的登录框,完美地在页面的正中间,不管你怎么缩放浏览器窗口,它永远在正中间!只需要三行核心代码,就实现了传统布局里无比复杂的水平垂直居中,这就是弹性布局的魅力!

取值 5:baseline(基线对齐)
  • 含义 :所有弹性项目,都以项目里第一行文字的基线对齐;

  • 大白话解释:什么是基线?我们写英文的四线三格,第三条线就是基线,所有的英文字母 x、a、s 的底部都在基线上,g、y、p 的下半部分会垂到基线下面;中文的汉字,基线就是汉字的底部。当设置了 baseline 对齐时,所有项目里的第一行文字的底部,都会对齐在同一条水平线上;

  • 默认侧轴(垂直)下的效果:哪怕项目的高度不一样,字号不一样,它们的第一行文字的底部,都会在同一条水平线上;

  • 适用场景:多个项目的文字字号不一样,需要让文字底部对齐的场景,比如图标和文字的对齐、不同字号的标题和描述的对齐;

  • 代码示例 :

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>align-items: baseline; 基线对齐</title>
      <style>
        .container {
          width: 500px;
          height: 200px;
          background-color: #f0f0f0;
          display: flex;
          align-items: baseline; /* 基线对齐 */
          justify-content: space-around;
          border: 2px solid #333;
        }
        .item1 {
          font-size: 12px;
          background-color: #007AFF;
          color: white;
          padding: 10px;
        }
        .item2 {
          font-size: 24px;
          background-color: #FF9500;
          color: white;
          padding: 20px;
        }
        .item3 {
          font-size: 36px;
          background-color: #34C759;
          color: white;
          padding: 30px;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <div class="item1">字号12px</div>
        <div class="item2">字号24px</div>
        <div class="item3">字号36px</div>
      </div>
    </body>
    </html>

    运行这段代码,你会看到:三个项目的字号、高度都不一样,但它们的文字底部,完美地对齐在同一条水平线上,这就是基线对齐的效果。

3.3.2 重点提醒:主轴变了,align-items 的控制方向也会变!

和justify-content一样,主轴的方向变了,侧轴的方向也会跟着变,align-items的控制方向也会变:

  • 当flex-direction: column;(主轴垂直),侧轴变成水平方向,align-items: center;就变成了水平居中,而不是垂直居中!
  • 很多新手在这里踩坑,一定要记住:align-items 永远管侧轴,侧轴永远和主轴垂直,主轴变了,它管的方向就变了!
3.3.3 避坑指南
  1. 坑 1:设置了 align-items: stretch,但是项目没有拉伸
    • 99% 的原因:你给项目显式设置了固定的 height(主轴 row 时),stretch 的前提是项目没有设置侧轴方向的固定尺寸,设置了就不会生效;
    • 解决方法:把项目的 height 改成 auto,或者删掉 height 的设置,stretch 就会生效;
  2. 坑 2:设置了 align-items: center,但是项目没有垂直居中
    • 原因 1:容器没有设置固定的 height,容器的高度是被项目撑开的,没有剩余的垂直空间,所以居中看不出来;
    • 解决方法:给容器设置明确的 height,比如height: 100vh;、height: 300px;,确保有剩余空间可以居中;
    • 原因 2:主轴是 column,align-items:center 是水平居中,不是垂直居中,垂直居中要用 justify-content:center;
    • 解决方法:先确定主轴和侧轴的方向,再写对应的属性;
  3. 坑 3:项目换行了,align-items 的效果和预期的不一样
    • 原因:align-items 只针对单行项目生效,如果项目换行了(有多行),要用 align-content 属性来控制多行的排列;
    • 解决方法:项目换行的时候,用 align-content 代替 align-items,我们后面会讲。

3.4 flex-wrap:控制弹性项目是否换行!(容器属性)

它是弹性布局里非常核心的基础属性,新手很容易在这里踩坑 ------ 为什么我的项目都挤在一行,都被压缩变形了,也不换行?就是因为没搞懂flex-wrap。

3.4.1 先搞懂:默认情况下,项目为什么不会换行?

默认情况下,flex-wrap的取值是nowrap(不换行),也就是说,不管弹性容器的宽度有多窄,所有的弹性项目都会拼命挤在一行里,不会自动换行。浏览器会自动压缩项目的宽度,来适应容器的宽度,哪怕项目设置了固定的 width,也会被压缩。

举个例子:容器宽度 400px,5 个项目,每个设置了 width:100px,总宽度 500px,超出了 100px。默认情况下,项目不会换行,浏览器会自动把每个项目的宽度压缩到 80px,刚好挤在一行里,不会换行。

这就是flex-wrap的作用:控制项目在容器空间不够的时候,要不要自动换行。

3.4.2 三个常用取值,每一个都讲透

flex-wrap一共有三个常用取值,我们一个一个地拆解。

取值 1:nowrap(默认值,不换行)
  • 含义 :所有弹性项目都排在一行 / 一列里,不会换行,哪怕容器的空间不够,浏览器会自动压缩项目的尺寸,强行挤进去;

  • 默认主轴(row)下的效果:项目永远排在一行,容器宽度不够就自动压缩,不会换到第二行;

  • 压缩规则 :默认每个项目的flex-shrink是 1(后面项目属性会讲),所以所有项目会等比例压缩;如果项目设置了min-width,浏览器不能压缩到 min-width 以下,项目就会超出容器的边界,不会换行;

  • 适用场景:需要项目永远排在一行的场景,比如导航栏、按钮组,容器宽度足够的情况下使用;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      flex-wrap: nowrap; /* 默认值,可以不写 */
    }
取值 2:wrap(换行,第一行在上面)
  • 含义 :当容器的主轴空间不够,排不下所有项目的时候,排不下的项目会自动换到新的一行,新的一行在原来一行的下面,不会压缩项目的尺寸;

  • 默认主轴(row)下的效果:项目先排在第一行,第一行排不下了,就自动换到第二行,第二行在第一行的下面,项目保持你设置的宽度,不会被压缩;

  • 适用场景:需要自适应换行的布局,比如商品卡片列表、图标列表、标签列表,是我们用得最多的取值;

  • 代码示例(来自你的资料的拓展) :

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>flex-wrap: wrap; 自动换行</title>
      <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
        .container {
          width: 400px; /* 容器只有400px宽 */
          height: auto; /* 高度自适应,方便看换行 */
          background-color: #f0f0f0;
          display: flex;
          flex-wrap: wrap; /* 自动换行 */
          /* 配合justify-content,让换行的项目也均匀分布 */
          justify-content: center;
          gap: 10px; /* 项目之间的间距,比margin更方便 */
          padding: 10px;
          margin: 20px;
          border: 2px solid #333;
        }
        .item {
          width: 100px; /* 每个项目100px宽,4个刚好填满一行,第5个就会换行 */
          height: 100px;
          background-color: #007AFF;
          color: white;
          font-size: 24px;
          display: flex;
          justify-content: center;
          align-items: center;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
        <div class="item">5</div>
        <div class="item">6</div>
      </div>
    </body>
    </html>

    运行这段代码,你会看到:前 4 个项目排在第一行,第 5、6 个项目自动换到了第二行,项目保持 100px 的宽度,没有被压缩,完美实现了自适应换行的效果,这就是flex-wrap: wrap;的作用。

取值 3:wrap-reverse(换行,第一行在下面,反向)
  • 含义 :当容器空间不够的时候,项目会自动换行,但新的一行在原来一行的上面,排列顺序反过来了;

  • 默认主轴(row)下的效果:第一行在最下面,第二行在第一行的上面,和 wrap 的顺序完全反过来;

  • 适用场景:很少用,了解即可,只有特殊的反向排版需求会用到;

  • 代码示例 :

    复制代码
    .container {
      display: flex;
      flex-wrap: wrap-reverse;
    }
3.4.3 避坑指南
  1. 坑 1:项目被压缩变形了,也不换行
    • 原因:默认 flex-wrap 是 nowrap,不换行,浏览器会自动压缩项目;
    • 解决方法:给容器设置flex-wrap: wrap;,空间不够的时候项目就会自动换行,不会被压缩;
  2. 坑 2:设置了 flex-wrap: wrap,但是项目还是不换行
    • 原因 1:项目没有设置固定的 width,项目的宽度是内容决定的,内容很短,永远能排在一行;
    • 解决方法:给项目设置固定的 width,确保一行排不下的时候会换行;
    • 原因 2:容器的宽度太大,足够放下所有项目,没有换行的必要;
    • 解决方法:缩小容器的宽度,或者增加项目的数量,让一行排不下;
  3. 坑 3:换行之后,行与行之间有很大的间距
    • 原因:默认 align-content 是 stretch,会拉伸行的高度,或者容器的高度太大,行与行之间有剩余空间;
    • 解决方法:用 align-content 属性控制多行的排列,我们后面会讲。

3.5 align-content:控制侧轴上的多行项目排列!(容器属性)

"align-items 只能针对单行元素来实现。如果有多行元素,就需要使用 align-content",这句话非常关键,我们现在就把这个属性讲透,让你知道什么时候用align-items,什么时候用align-content。

3.5.1 先搞懂:align-content 和 align-items 的核心区别

很多新手搞不清这两个属性的区别,我用一句话给你讲明白:

  • align-items :控制每一行里的项目,在当前行的侧轴方向上的对齐方式,针对的是 "单个项目";
  • align-content :控制所有的行,在整个容器的侧轴方向上的排列方式,针对的是 "整行",分配的是行与行之间的剩余空间;
  • 核心前提 :align-content只有在项目换行了(flex-wrap: wrap),有多行项目的时候,才会生效!如果只有一行项目,不管你设置什么 align-content,都不会有任何效果,因为只有一行,没有行与行之间的剩余空间可以分配!

举个通俗的例子:

  • 你在教室里排座位,排了 3 行,每行 5 个同学:
    • align-items:控制每一行里的同学,在这一行里是靠前坐、靠后坐、还是居中坐;
    • align-content:控制这 3 行座位,在整个教室里是靠讲台排、靠后墙排、还是均匀分布在教室里。
3.5.2 六个常用取值,和 justify-content 完全对应

align-content的取值,和justify-content的取值几乎完全一样,只是justify-content分配的是主轴上项目之间的剩余空间,align-content分配的是侧轴上行与行之间的剩余空间,记忆起来非常简单。

我们以默认主轴 row、flex-wrap: wrap、有多行项目为例,讲解每一个取值:

  1. stretch(默认值):所有行的高度会自动拉伸,填满整个容器的侧轴高度,行与行之间没有剩余空间;
  2. flex-start:所有行都紧贴着侧轴的起点(容器顶部)排列,剩余空间全部放在侧轴终点(容器底部);
  3. flex-end:所有行都紧贴着侧轴的终点(容器底部)排列,剩余空间全部放在侧轴起点(容器顶部);
  4. center:所有行在侧轴的正中间排列,剩余空间平均分配在容器的顶部和底部;
  5. space-around:剩余空间平均分配给每一行的上下两侧,行与行之间的间距是两端间距的两倍;
  6. space-between:第一行紧贴侧轴起点,最后一行紧贴侧轴终点,剩余空间平均分配在行与行之间;
3.5.3 代码示例:align-content 的直观效果

我们写一个完整的代码示例,对比align-items和align-content的区别,以及align-content各个取值的效果:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>align-content 多行排列对比</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .demo {
      margin: 20px;
      padding: 10px;
      border: 2px solid #333;
      display: inline-block;
      vertical-align: top;
    }
    .container {
      width: 420px;
      height: 400px; /* 固定高度,有剩余空间 */
      background-color: #f0f0f0;
      display: flex;
      flex-direction: row;
      flex-wrap: wrap; /* 必须换行,有多行,align-content才会生效 */
      gap: 10px;
      padding: 10px;
    }
    .item {
      width: 120px;
      height: 100px;
      background-color: #007AFF;
      color: white;
      font-size: 24px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    /* 不同的align-content取值 */
    .stretch { align-content: stretch; }
    .flex-start { align-content: flex-start; }
    .flex-end { align-content: flex-end; }
    .center { align-content: center; }
    .space-around { align-content: space-around; }
    .space-between { align-content: space-between; }
  </style>
</head>
<body>
  <div class="demo">
    <h3>align-content: stretch;(默认,拉伸行高)</h3>
    <div class="container stretch">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
      <div class="item">4</div>
      <div class="item">5</div>
      <div class="item">6</div>
    </div>
  </div>

  <div class="demo">
    <h3>align-content: flex-start;(紧贴顶部)</h3>
    <div class="container flex-start">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
      <div class="item">4</div>
      <div class="item">5</div>
      <div class="item">6</div>
    </div>
  </div>

  <div class="demo">
    <h3>align-content: center;(垂直居中)</h3>
    <div class="container center">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
      <div class="item">4</div>
      <div class="item">5</div>
      <div class="item">6</div>
    </div>
  </div>

  <div class="demo">
    <h3>align-content: space-between;(两端对齐)</h3>
    <div class="container space-between">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
      <div class="item">4</div>
      <div class="item">5</div>
      <div class="item">6</div>
    </div>
  </div>
</body>
</html>

运行这段代码,你会直观地看到align-content各个取值的效果,以及它和align-items的区别:它控制的是整行的排列,而不是单个项目的排列。

3.5.4 避坑指南
  1. 坑 1:设置了 align-content,但是没有任何效果
    • 99% 的原因:项目没有换行,只有一行,align-content 只对多行项目生效;
    • 解决方法:给容器设置flex-wrap: wrap;,让项目换行,有多行项目,align-content 才会生效;
  2. 坑 2:搞反了 align-items 和 align-content 的使用场景
    • 解决方法:记住一句话 ------ 单行用 align-items,多行用 align-content;
  3. 坑 3:容器没有固定的 height,align-content 不生效
    • 原因:容器的 height 是 auto,被项目的高度撑开了,没有剩余的侧轴空间,无法分配行与行之间的空间;
    • 解决方法:给容器设置明确的 height,确保有剩余的侧轴空间,align-content 才会有效果。

四、弹性项目的核心属性:控制单个项目的特殊规则

前面我们讲的,都是设置在弹性容器上的属性,控制所有项目的整体排列。但有时候,我们需要给某个单独的项目设置特殊的规则,比如让某个项目单独靠右、单独放大、单独底部对齐,这时候,就需要用到设置在弹性项目上的属性。

这部分属性虽然没有容器属性用得频繁,但也是弹性布局的核心,能让你的布局更灵活,我们一个一个地拆到极致,讲透底层原理和适用场景。

4.1 flex-grow:项目的放大比例,分配剩余空间

flex-grow是弹性项目的 "放大比例",它决定了当容器主轴方向有剩余空间的时候,这个项目能分到多少剩余空间,默认值是 0,也就是不放大。

4.1.1 底层原理:怎么分配剩余空间?

我们还是用具体的数字例子,给你算得明明白白:

  • 前提:容器宽度 500px,主轴水平,3 个项目,每个项目的宽度是 100px,总宽度 300px,剩余空间 200px;
  • flex-grow的取值,是一个没有单位的正数,代表放大的比例;
  • 浏览器会把所有项目的flex-grow值加起来,得到一个总份数,然后把剩余空间按照份数,分配给每个项目,项目的flex-grow值越大,分到的剩余空间越多,项目就越宽。
4.1.2 具体例子,每一种情况都讲透
情况 1:所有项目的 flex-grow 都是 0(默认)
  • 总份数:0+0+0=0;
  • 剩余空间不分配,项目保持 100px 的宽度,剩余 200px 在容器右侧;
情况 2:项目 1 的 flex-grow 是 1,其他两个是 0
  • 总份数:1+0+0=1;
  • 剩余的 200px 全部分给项目 1,项目 1 的最终宽度 = 100 + 200 = 300px;
  • 其他两个项目保持 100px 的宽度;
情况 3:项目 1 的 flex-grow 是 1,项目 2 是 1,项目 3 是 2
  • 总份数:1+1+2=4;
  • 每份的大小:200px / 4 = 50px;
  • 项目 1 分到 50px,最终宽度 = 100+50=150px;
  • 项目 2 分到 50px,最终宽度 = 100+50=150px;
  • 项目 3 分到 100px,最终宽度 = 100+100=200px;
4.1.3 经典应用:等分布局

flex-grow最经典的应用,就是实现等分布局 :给所有项目设置flex-grow: 1;,同时设置flex-basis: 0;(后面会讲),那么所有项目会等宽,不管容器宽度是多少,每个项目都是 1/3 宽度(3 个项目的话)。

代码示例:

html 复制代码
.container {
  display: flex;
  width: 500px;
  height: 100px;
}
.item {
  flex-grow: 1; /* 所有项目放大比例都是1,平分剩余空间 */
  flex-basis: 0; /* 基准宽度为0,所有空间都当成剩余空间分配 */
  height: 100px;
  border: 1px solid #333;
}
4.1.4 避坑指南
  1. 坑 1:以为 flex-grow:1 就是项目宽度 1 份,结果项目宽度不一样
    • 原因:默认 flex-basis 是 auto,项目的基准宽度是本身的 width,剩余空间是容器宽度减去所有项目的总宽度,所以项目的最终宽度是 "基准宽度 + 分到的剩余空间",如果基准宽度不一样,最终宽度也不一样;
    • 解决方法:给项目设置flex-basis: 0;,让所有项目的基准宽度都是 0,所有空间都当成剩余空间分配,就能实现真正的等宽;
  2. 坑 2:flex-grow 设置了负数,无效
    • 原因:flex-grow 的取值只能是 0 或者正数,负数是无效的,浏览器会忽略;
    • 解决方法:flex-grow 只设置 0 或者正数。

4.2 flex-shrink:项目的缩小比例,处理超出空间

flex-shrink是弹性项目的 "缩小比例",它决定了当容器主轴空间不够,项目总宽度超过容器宽度的时候,这个项目要缩小多少,默认值是 1,也就是所有项目等比例缩小。

4.2.1 底层原理:怎么分配超出的空间?

我们还是用具体的数字例子:

  • 前提:容器宽度 400px,主轴水平,4 个项目,每个项目的宽度是 120px,总宽度 480px,超出了 80px;
  • flex-shrink的取值,是一个没有单位的正数,代表缩小的比例,默认值是 1;
  • 浏览器会把所有项目的flex-shrink值加起来,得到总份数,然后把超出的空间,按照份数分配给每个项目,项目的flex-shrink值越大,缩小的越多;如果flex-shrink是 0,项目不会缩小,会超出容器。
4.2.2 具体例子
情况 1:所有项目的 flex-shrink 都是 1(默认)
  • 总份数:1+1+1+1=4;
  • 超出的 80px,每个项目缩小 80/4=20px;
  • 每个项目的最终宽度 = 120-20=100px,刚好挤在一行里;
情况 2:项目 1 的 flex-shrink 是 0,其他三个是 1
  • 总份数:0+1+1+1=3;
  • 超出的 80px,由其他三个项目承担,每个缩小 80/3≈26.67px;
  • 项目 1 保持 120px 的宽度,不会缩小;
  • 其他三个项目的最终宽度 = 120-26.67≈93.33px;
情况 3:项目 1 的 flex-shrink 是 3,其他三个是 1
  • 总份数:3+1+1+1=6;
  • 超出的 80px,每份 80/6≈13.33px;
  • 项目 1 缩小 3*13.33≈40px,最终宽度 80px;
  • 其他三个项目缩小 13.33px,最终宽度≈106.67px;
4.2.3 避坑指南
  1. 坑 1:项目设置了 min-width,flex-shrink 不生效
    • 原因:浏览器不能把项目的宽度压缩到 min-width 以下,所以哪怕设置了 flex-shrink,项目也不会缩小到 min-width 以下,会超出容器;
    • 解决方法:如果需要项目缩小,不要设置 min-width,或者把 min-width 设置得小一点;
  2. 坑 2:flex-shrink 设置了负数,无效
    • 原因:flex-shrink 的取值只能是 0 或者正数,负数无效;
    • 解决方法:flex-shrink 只设置 0 或者正数。

4.3 flex-basis:项目在主轴上的基准尺寸

flex-basis是弹性项目在主轴方向上的基准尺寸,也就是浏览器在计算剩余空间或者超出空间的时候,用的项目的基准宽度 / 高度,默认值是 auto。

4.3.1 核心规则:优先级比 width/height 高!

当主轴是水平方向的时候,flex-basis的优先级比width高!如果项目同时设置了width和flex-basis,浏览器会优先使用flex-basis的值,作为项目的基准尺寸,width会被忽略。

举个例子:项目设置了width: 100px; flex-basis: 150px;,那么浏览器计算的时候,项目的基准宽度是 150px,不是 100px。

4.3.2 常用取值
  1. auto(默认值) :项目的基准尺寸,等于项目本身的width/height值,如果没有设置宽高,就由内容的大小决定;
  2. 具体数值 + 单位 :比如100px、50%,项目的基准尺寸就是这个固定值;
  3. 0 :项目的基准尺寸是 0,不管项目本身的 width 是多少,浏览器都会把它的基准尺寸当成 0,所有的容器空间都会被当成剩余空间,按照flex-grow的比例分配,这是实现等分布局的关键。
4.3.3 避坑指南
  1. 坑 1:同时设置了 width 和 flex-basis,width 不生效
    • 原因:flex-basis 的优先级比 width 高,浏览器会优先使用 flex-basis 的值;
    • 解决方法:如果需要固定项目的宽度,只设置 flex-basis 就可以了,不用设置 width;
  2. 坑 2:主轴是 column 的时候,flex-basis 控制的是 height,不是 width
    • 原因:flex-basis 控制的是主轴方向的基准尺寸,主轴是垂直的时候,它控制的是 height,不是 width;
    • 解决方法:主轴是 column 的时候,用 flex-basis 控制项目的高度,不用设置 height。

4.4 flex:项目属性的简写属性(重点!)

flex是flex-grow、flex-shrink、flex-basis三个属性的简写属性,写法是:

复制代码
flex: flex-grow flex-shrink flex-basis;

这是我们实际开发中最常用的写法,推荐大家永远用简写属性,不要分开写三个属性,代码更简洁,也不容易出错。

4.4.1 常用的简写值,每一个都讲透
  1. flex: 0 1 auto;(默认值):等价于不写 flex 属性,也就是不放大、可缩小、基准尺寸 auto;
  2. flex: 1; :等价于flex: 1 1 0;,也就是放大比例 1、缩小比例 1、基准尺寸 0,最常用在等分布局、自适应宽度的项目上;
  3. flex: auto; :等价于flex: 1 1 auto;,也就是放大比例 1、缩小比例 1、基准尺寸 auto,项目会根据内容的大小自动放大缩小;
  4. flex: none; :等价于flex: 0 0 auto;,也就是不放大、不缩小、基准尺寸 auto,项目的宽度固定,不会放大也不会缩小,常用在固定宽度的项目上。
4.4.2 避坑指南
  1. 坑 1:简写的顺序写错了,样式不生效
    • 原因:flex 简写的顺序必须是 grow、shrink、basis,顺序错了浏览器会解析错误;
    • 解决方法:严格按照flex: grow shrink basis;的顺序写;
  2. 坑 2:只写了一个数值,以为是 flex-basis,结果是 flex-grow
    • 原因:如果 flex 简写只写了一个数值,浏览器会把它当成 flex-grow 的值,flex-shrink 默认 1,flex-basis 默认 0;
    • 解决方法:如果要设置 flex-basis,必须带单位,比如flex: 0 0 100px;,不带单位的数值会被当成 flex-grow。

4.5 align-self:给单个项目设置侧轴对齐方式,覆盖容器的 align-items

align-self的作用是:给单个弹性项目设置侧轴方向的对齐方式,覆盖弹性容器设置的align-items属性。

容器的align-items是给所有项目设置统一的侧轴对齐,而align-self是给某个项目单独设置,不影响其他项目,取值和align-items完全一样:auto(默认,继承容器的 align-items)、flex-start、flex-end、center、stretch、baseline。

4.5.1 代码示例:单个项目单独底部对齐
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>align-self 单个项目单独对齐</title>
  <style>
    .container {
      width: 500px;
      height: 300px;
      background-color: #f0f0f0;
      display: flex;
      align-items: center; /* 所有项目默认垂直居中 */
      justify-content: space-around;
      border: 2px solid #333;
    }
    .item {
      width: 100px;
      background-color: #007AFF;
      color: white;
      font-size: 24px;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 10px;
    }
    /* 给第三个项目单独设置align-self,覆盖容器的align-items */
    .item-bottom {
      align-self: flex-end; /* 单独底部对齐 */
      background-color: #FF9500;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item item-bottom">3</div>
    <div class="item">4</div>
  </div>
</body>
</html>

运行这段代码,你会看到:所有项目默认都是垂直居中,只有第三个橙色的项目,单独贴在了容器的底部,其他项目不受影响,这就是align-self的作用。

4.5.2 适用场景
  • 卡片布局里,某个按钮需要单独贴在底部;
  • 导航栏里,某个菜单需要单独靠右对齐;
  • 表单里,某个输入框需要单独顶部对齐;
  • 任何需要单个项目和其他项目对齐方式不一样的场景。

4.6 order:控制项目的排列顺序

order属性用来控制弹性项目的排列顺序,默认值是 0,项目的order值越小,排列越靠前;order值越大,排列越靠后。

4.6.1 代码示例:改变项目的排列顺序
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>order 改变项目排列顺序</title>
  <style>
    .container {
      width: 500px;
      height: 100px;
      background-color: #f0f0f0;
      display: flex;
      justify-content: space-around;
      align-items: center;
    }
    .item {
      width: 80px;
      height: 80px;
      background-color: #007AFF;
      color: white;
      font-size: 24px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    /* 改变项目的order值 */
    .item1 { order: 3; } /* 原来的第一个项目,order3,排到最后 */
    .item2 { order: 1; } /* 原来的第二个项目,order1,排到最前 */
    .item3 { order: 2; } /* 原来的第三个项目,order2,排中间 */
  </style>
</head>
<body>
  <div class="container">
    <div class="item item1">1</div>
    <div class="item item2">2</div>
    <div class="item item3">3</div>
  </div>
</body>
</html>

运行这段代码,你会看到:HTML 里的顺序是 1、2、3,但页面上的排列顺序是 2、3、1,因为我们通过order属性改变了它们的排列顺序,HTML 结构不需要做任何修改。

4.6.2 适用场景
  • 响应式布局里,移动端需要改变项目的排列顺序,比如 PC 端是图片在左、文字在右,移动端需要文字在上、图片在下,不用改 HTML,只用改 order;
  • 特殊的排版需求,需要调整项目的顺序,但不想修改 HTML 结构;
  • SEO 优化,HTML 里把重要的内容放在前面,页面上用 order 调整显示顺序。

五、避坑指南

我把新手学弹性布局时,100% 会踩的坑,全部整理出来,每一个坑都讲清楚原因和解决方法,让你少走 90% 的弯路。

  1. 坑 1:忘记给父元素加 display:flex,所有 flex 属性都不生效

    • 原因:所有的 flex 属性,都是建立在父元素是弹性容器的基础上的,没加 display:flex,写再多属性都没用;
    • 解决方法:每次写弹性布局,第一行先给父元素加 display:flex,养成习惯!
  2. 坑 2:搞不清主轴和侧轴,justify-content 和 align-items 用反了

    • 原因:没搞懂主轴的方向,主轴变了,两个属性的控制方向也变了;
    • 解决方法:每次用这两个属性之前,先看 flex-direction,确定主轴和侧轴,记住:justify-content 永远管主轴,align-items 永远管侧轴。
  3. 坑 3:给弹性项目写了 float、clear、vertical-align,完全不生效

    • 原因:弹性项目的这三个属性会被浏览器直接忽略,弹性布局有自己的排列规则,不需要浮动;
    • 解决方法:不要给弹性项目写这三个属性,用弹性布局的属性实现对应的效果。
  4. 坑 4:设置了 align-items:stretch,项目没有拉伸

    • 原因:给项目显式设置了固定的 height(主轴 row 时),stretch 只在项目 height 为 auto 的时候生效;
    • 解决方法:删掉项目的固定 height,或者改成 auto。
  5. 坑 5:写了 justify-content/align-items:center,项目没有居中

    • 原因 1:容器没有固定的尺寸,没有剩余空间,居中看不出来;
    • 解决方法:给容器设置明确的 width/height,确保有剩余空间;
    • 原因 2:主轴和侧轴搞反了,属性用反了;
    • 解决方法:先确定主轴方向,再写对应的属性。
  6. 坑 6:项目被压缩变形,也不换行

    • 原因:默认 flex-wrap 是 nowrap,不换行,浏览器会自动压缩项目;
    • 解决方法:给容器设置 flex-wrap:wrap,让项目自动换行。
  7. 坑 7:设置了 align-content,完全没效果

    • 原因:项目没有换行,只有一行,align-content 只对多行项目生效;
    • 解决方法:设置 flex-wrap:wrap,让项目换行,有多行项目。
  8. 坑 8:属性名拼写错误,样式不生效

    • 常见错误:margin 写成 marign、flex 写成 flexe、justify 写成 justity、align 写成 algin、content 写成 conten;
    • 解决方法:写代码的时候仔细检查,用代码编辑器的语法提示,避免拼写错误。
  9. 坑 9:用了 space-between,最后一行项目数量不够,排列乱了

    • 原因:space-between 是两端对齐,最后一行项目少的话,会出现一个贴左、一个贴右的情况;
    • 解决方法:给容器加几个空的弹性项目,宽度和正常项目一样,没有内容,填满最后一行,或者用 grid 布局。
  10. 坑 10:给孙子元素设置 flex 属性,完全不生效

    • 原因:弹性容器只能控制直接子元素,孙子元素不受影响;
    • 解决方法:给孙子元素的父元素(直接子元素)也设置 display:flex,让它也变成弹性容器。
  11. 坑 11:项目设置了 position:absolute,不受 flex 属性控制

    • 原因:绝对定位的元素脱离了文档流,不再是弹性项目,不受弹性容器的控制;
    • 解决方法:如果需要项目参与弹性排列,不要设置 position:absolute。
  12. 坑 12:弹性容器的高度没设置,align-items:center 不生效

    • 原因:容器高度是 auto,被项目撑开了,没有剩余的垂直空间,居中没有效果;
    • 解决方法:给容器设置明确的 height,比如 height:100vh、height:300px。

结语

恭喜你!坚持看到这里,你已经把弹性布局的所有核心知识点,从基础概念、容器属性、项目属性,到避坑指南、实战案例,全部都吃透了!

我们用一段话,把所有核心知识点串起来,帮你巩固记忆:

弹性布局的核心,是弹性容器 和弹性项目 两个角色,给父元素设置display:flex;,它就变成了弹性容器,直接子元素自动变成弹性项目。容器有两个轴:主轴 (项目排列的主方向,由flex-direction决定)和侧轴(永远和主轴垂直)。容器的核心属性:

  1. flex-direction:决定主轴方向(row/row-reverse/column/column-reverse);
  2. justify-content:控制主轴上的项目排列(flex-start/flex-end/center/space-around/space-between);
  3. align-items:控制侧轴上的单行项目排列(stretch/flex-start/flex-end/center/baseline);
  4. flex-wrap:控制项目是否换行(nowrap/wrap/wrap-reverse);
  5. align-content:控制侧轴上的多行项目排列。项目的核心属性:
  6. flex:简写属性,控制项目的放大、缩小、基准尺寸;
  7. align-self:给单个项目设置侧轴对齐,覆盖容器的 align-items;
  8. order:控制项目的排列顺序。经典应用:三行代码实现水平垂直居中(display:flex; justify-content:center; align-items:center;)!

最后,给新手的学习建议:不要死记硬背属性的取值,要理解底层逻辑,多写多练,多用 Chrome 调试工具的 Flex 面板,遇到问题先排查有没有加 display:flex、主轴和侧轴有没有搞对、有没有剩余空间。弹性布局是现代前端开发的核心技能,你只要彻底搞懂了它,90% 的 CSS 布局问题都能迎刃而解!

这篇超详细的弹性布局解析到这里就结束了,希望能给零基础的你,带来实实在在的帮助。如果有任何问题,或者想学习更多 CSS 的进阶内容,都可以在评论区留言,我们一起交流学习。

感谢阅读,我们下篇文章再见!

相关推荐
山雀~1 小时前
第5次百日救赎计划
前端
xiaogai_gai1 小时前
销售出库单同步实战:旺店通→金蝶云星空的单一策略深度拆解
大数据·前端·数据库
const_qiu1 小时前
第二章 2.6:初始化 NestJS 服务端 —— TypeScript 后端框架体验
前端·javascript·typescript
云老大-阿里云国际站代理商2 小时前
华为云国际站渠道代理商:CSS查询很慢但CPU不高?磁盘I/O、JVM与分片问题怎么排查
css·jvm·华为云
console.log('npc')2 小时前
[特殊字符] AI Agent 工作台前端实战教程 · 新手入门指南
前端·人工智能
gCode Teacher 格码致知2 小时前
前端教学2:ul标签的应用场合与经典案例
前端
voipmaker2 小时前
选煤厂智能化:UWB 人员定位系统 WebAPI 对接融合通信平台实战
物联网·实时互动·json·音视频·实时音视频·web·视频
const_qiu2 小时前
第 2.5 章 2.5.6:前端登录、Token 无感续签与路由守卫
java·前端·人工智能·状态模式