CSS探索系列之flex布局

浏览器仍按 CSS 基础框盒模型(CSS basic box model) 把元素画成矩形:内容、内边距、边框、外边距

Flex 改的不是盒模型本身,而是这些盒子沿一根轴怎么排、剩余空间怎么分。

传统方案靠 displaypositionfloat 拼布局,垂直居中、等分栏都很别扭。弹性盒子布局(Flexible Box Layout,Flex) 是面向 UI 的一维布局:弹性项目可沿任意方向排布,既能撑满剩余空间,也能收缩以免撑破容器,主轴和交叉轴上的对齐都能直接控制。

基本概念

Flex 一次只处理一个维度,一行或一列。要同时管行和列,用 网格布局

image-20200612003555661

.container {
    display: flex;        /* 块级弹性容器 */
}
.container {
    display: inline-flex; /* 行内级弹性容器 */
}

display: flexinline-flex 会建立弹性格式化上下文(Flex Formatting Context,FFC),不是 BFC。容器叫弹性容器,它的每个子元素都是弹性项目(含 ::before::after)。文本节点会生成匿名弹性项目。绝对定位的子元素不参与弹性排版。

一套弹性布局有两根轴:

  • 主轴(main axis):项目依次排列的方向,由 flex-direction 决定。
  • 交叉轴(cross axis,也称侧轴):垂直于主轴的那根轴。

刚建成的弹性容器,项目有一套默认行为:沿主轴排成一行(flex-direction: row)、从主轴起点起排、主轴方向默认不放大但可缩小、交叉轴默认被拉齐flex-basis: autoflex-wrap: nowrap。项目过多时默认溢出,不换行。

下列属性在弹性布局里失去原意:

  • 多栏模块的 column-*弹性容器无效。
  • floatclear弹性项目无效,不会把项目拿出弹性布局。
  • vertical-align 对弹性项目的对齐无效。

容器的属性

设置在弹性容器上:

  1. flex-direction
  2. flex-wrap
  3. flex-flow
  4. justify-content
  5. align-items
  6. align-content
  7. place-content
  8. gaprow-gapcolumn-gap

flex-direction

定义主轴方向,也就是项目的排列方向。

初始值:row

  • row:主轴沿行向(inline),从主轴起点到终点。
  • row-reverse:主轴沿行向,起点与终点对调。
  • column:主轴沿块向(block),从块起点到块终点。
  • column-reverse:主轴沿块向,起点与终点对调。

image-20200612004410287

排列方向

  • rowrow-reverse:沿行内轴排布,受 writing-modedirection 共同影响。
    • horizontal-tb 模式中行内轴为水平方向;
    • direction: ltrrow 从左到右,direction: rtlrow 从右到左,row-reverse 顺序相反。
    • 在竖排模式下,行内轴切换为垂直方向,row 不再是横向排列。
  • columncolumn-reverse:沿块轴排布,排布方向仅由 writing-mode 决定,不受 direction 影响。
    • horizontal-tb:块轴自上而下,column 从上至下排列;
    • vertical-rl:块轴自右向左,column 从容器右侧向左侧依次排列;
    • vertical-lr:块轴自左向右,column 从容器左侧向右侧依次排列;
    • column-reverse 为对应方向反转。

flex-wrap

指定项目单行还是多行。多行时,它还决定行在交叉轴上的堆叠方向。

初始值:nowrap

  • nowrap:所有项目放在一行,挤不下就溢出或按 flex-shrink 收缩。
  • wrap:换行,新行沿交叉轴正方向堆叠(水平书写时由上往下)。
  • wrap-reverse:换行,新行沿交叉轴反方向堆叠(水平书写时由下往上),交叉轴起点与终点对调。

image-20200612011228246

flex-flow

flex-directionflex-wrap 的简写。初始值:row nowrap

flex-flow: column-reverse wrap;

justify-content

定义项目在主轴上的对齐,以及主轴剩余空间怎么分。

初始值:normal。在弹性布局里表现与 flex-start 相同。

常用值:

  • flex-start:靠主轴起点。
  • flex-end:靠主轴终点。
  • center:主轴居中。
  • space-between:两端贴边,项目之间间隔相等。
  • space-around:每个项目两侧间隔相等,因此项目之间的间隔是项目与容器边缘间隔的两倍。
  • space-evenly:项目之间、项目与容器边缘之间的间隔都相等。

其余取值(存在浏览器兼容限制):

  • startend:逻辑对齐,跟随书写方向起点、终点,不绑定 Flex 主轴;flex-startflex-end 严格跟随主轴方向。旧版 Safari、IE11 不支持。
  • leftright:物理左、右对齐。主轴为垂直方向(columncolumn-reverse)时,无法匹配水平物理轴,自动按 start 处理。
  • stretch:仅在 Grid 主轴有效;弹性布局主轴上不生效,尺寸由 flex 伸缩算法决定。
  • safeunsafe:溢出修饰符,必须搭配对齐关键字使用。safe 在内容溢出容器时自动降级为起点对齐;unsafe 坚持目标对齐,允许内容溢出。需要较高浏览器版本,移动端低版本 Safari、小程序谨慎使用

image-20200612225416483

备注: 弹性项目的 margin: auto 会先吃掉主轴(或交叉轴)上的剩余空间,再轮到 justify-contentalign-items。主轴两侧都写成 auto,项目会在主轴上居中。

align-items

定义项目在交叉轴上如何对齐。

初始值:normal。在弹性布局里表现与 stretch 相同。

常用值:

  • flex-start:靠交叉轴起点。
  • flex-end:靠交叉轴终点。
  • center:交叉轴居中。
  • baseline:按第一行文字基线对齐。
  • stretch:项目在交叉轴上拉伸填满容器;前提是项目交叉轴尺寸为 auto,且没有限制拉伸。

其余取值(存在浏览器兼容限制):

  • startend:逻辑对齐,跟随容器书写方向起点、终点,不绑定 Flex 交叉轴;flex-startflex-end 严格跟随交叉轴。旧版 Safari、IE11 不支持。
  • self-startself-end:跟随单个弹性项目自身的书写方向对齐。旧版 Safari、IE11 不支持。
  • first baselinelast baseline:显式指定使用第一基线、最后基线对齐;通用简写 baseline 等效于 first baseline,兼容性更好。旧版 Safari、IE11 不支持。
  • safeunsafe:溢出修饰符,必须搭配对齐关键字使用。含义与 justify-content 相同。需要较高浏览器版本,移动端低版本 Safari、小程序谨慎使用

image-20200612232910010

align-content

弹性容器分多行时,定义各行在交叉轴上的对齐和空间分配。单行容器(flex-wrap: nowrap,或项目并未换行)上无效。

初始值:normal。在弹性布局里表现与 stretch 相同。

常用值:

  • flex-start:各行靠交叉轴起点。
  • flex-end:各行靠交叉轴终点。
  • center:各行整体居中。
  • space-between:首尾行贴边,行与行间隔平均。
  • space-around:每行两侧间隔相等,行与行之间的间隔是行与边缘间隔的两倍。
  • space-evenly:行与行、行与边缘的间隔都相等。
  • stretch:各行被拉大,占满交叉轴。

其余取值(存在浏览器兼容限制):

  • startend:逻辑对齐,跟随书写方向起点、终点,不绑定 Flex 交叉轴。旧版 Safari、IE11 不支持。
  • baselinefirst baselinelast baseline:按各行基线对齐。旧版 Safari、IE11 不支持。
  • safeunsafe:溢出修饰符,必须搭配对齐关键字使用。含义与 justify-content 相同。需要较高浏览器版本,移动端低版本 Safari、小程序谨慎使用

image-20200613000900833

place-content

align-contentjustify-content 的简写:第一个值给交叉轴,第二个值给主轴。取值分别沿用这两个属性的常用值、其余取值。

place-content: center space-between;

注意: 只写一个值时,若该值对两个属性都合法,则两个属性都用它;对其中任何一个不合法,整条声明无效。

其余取值(存在浏览器兼容限制):

  • 属性本身:IE11、旧版 Edge 不支持;Safari 9 起可用。
  • 写成 startendsafe 等时,兼容限制与 align-contentjustify-content 的其余取值相同。需要兼容旧环境时,拆开写 align-contentjustify-content 的常用值。

gap

gap(以及 row-gapcolumn-gap)设置项目之间的间距,不作用到容器内边缘。flex-direction: row 时,主轴间隔对应 column-gap,交叉轴上行与行的间隔对应 row-gapflex-direction: column 时对调。gap 不计入 flex-basis,用百分比分栏时要把间隙从项目尺寸里扣掉。

常用值:长度、百分比,如 gap: 16pxgap: 8px 12px

属性浏览器兼容:弹性容器上的 gap,IE11 不支持;Safari 需 14.1+(iOS Safari 14.5+)。

项目的属性

设置在弹性项目上:

  1. order
  2. flex-grow
  3. flex-shrink
  4. flex-basis
  5. flex
  6. align-self

order

定义项目的视觉排列顺序。数值越小越靠前,默认 0,可取负整数。只改视觉顺序,不改源码顺序、Tab 顺序和读屏顺序。

flex-grow

指定项目怎么分主轴上的剩余空间。剩余空间 = 容器主轴内尺寸 − 该行所有项目的主轴尺寸之和。

初始值:0(有剩余空间也不放大)。大于 0 才参与分配。负值无效。

  • 把所有参与放大的 flex-grow 加总,记为总和。
  • 总和 ≥ 1:剩余空间分光,每项分到的份额按各自 flex-grow 占总和的比例。三个项目为 1 : 2 : 1 时,值为 2 的拿到剩余空间的 2/4
  • 总和 < 1:只分配「剩余空间 × 总和」那么多,容器里仍留空。只有一项且值为 0.5,它只吃掉一半剩余空间。
  • 只有一项且值 ≥ 1:它吃掉全部剩余空间。

image-20200613141809054

flex-shrink

指定项目在主轴空间不够时怎么收缩。默认会收缩;flex-wrap: wrap 换行之后,每一行单独算,不一定再收缩。

不足空间 = 该行项目主轴尺寸之和 − 容器主轴内尺寸。

初始值:10 表示不收缩。负值无效。

收缩不是按 flex-shrink 值直接等比,而是按加权收缩因子

加权收缩因子 = flex-shrink × 该项目的弹性基准尺寸(inner flex base size)
某项收掉的不足空间 = 不足空间 × (该项加权因子 / 所有项加权因子之和)

同样是 flex-shrink: 1,基准尺寸更大的项目会多收一截,避免小项目先被收到 0。

  • 所有加权因子之和对应的收缩比例 < 1(各 flex-shrink 之和 < 1,且按上面公式折算后仍吃不完)时,不足空间不会被完全消化,容器仍溢出。
  • 一项 flex-shrink: 0、其余为 1:空间不足时前者不缩小。

image-20200613143309096

flex-basis

指定项目在主轴上的初始主尺寸(弹性基准)。浏览器先按它算出有没有剩余空间,再做 grow、shrink。

初始值:auto

常用值:

  • auto:先看主轴方向上的 widthflex-direction: column 时看 height)。那边也是 auto,就按内容尺寸,等价于 content
  • <width>:与 widthheight 相同的长度或百分比(如 350px2rem30%)。负值无效。百分比相对弹性容器的主轴内尺寸;容器主轴尺寸不定时,百分比按 content 解析。

其余取值(存在浏览器兼容限制):

  • content:按内容自动确定基准,忽略 widthheight。旧版 Safari、IE11 不支持。
  • max-contentmin-contentfit-content:按固有尺寸关键词确定基准。旧版 Safari、IE11 不支持。需要兼容时,用 auto 或明确的长度代替。

注意: flex-basis 不为 auto 时,它覆盖主轴方向上的 width(或 height)。最终用到的主尺寸还要经过 grow、shrink 和 min、max 限制,见下文「弹性项目尺寸的计算」。

早期规范一度把 auto 改成「自动尺寸」、另造 main-size 去参照宽高,后来撤销。现在的分工就是:auto 参照宽高,content 表示按内容自动尺寸。

flex

flex-growflex-shrinkflex-basis 的简写,后两项可省略。

初始值:0 1 auto,关键字 initial 即此值。

  • 一个值
    • 无单位数字:当作 flex-grow。规范展开为 n 1 0;现行浏览器把省略的基准写成 0%。容器主轴尺寸不定时,0% 会按 content 解析,和长度 0 不同。
    • 合法的宽度值:当作 flex-basis,grow、shrink 分别为 1
    • auto1 1 auto
    • none0 0 auto(不放大、不缩小)
    • initial0 1 auto
  • 两个值:第一个必须是无单位数字,当作 flex-grow。第二个要么是无单位数字(flex-shrink),要么是宽度值(flex-basis)。
  • 三个值:grow、shrink、basis,按这个顺序。

单独写 flex-grow: 1 时,另外两项仍是初始值 0 1 auto。写成 flex: 1 时,没写出的分量按简写规则补全,和初始值不是同一套。要跟内容宽度挂钩再分剩余空间,用 flex: auto

align-self

覆盖单个项目的交叉轴对齐,把容器的 align-items 顶掉。

初始值:auto,表示用父元素的 align-items;没有弹性父元素时按 stretch

常用值:

  • auto:继承容器的 align-items
  • flex-startflex-endcenterbaselinestretch:含义与 align-items 的常用值相同。

其余取值(存在浏览器兼容限制):

  • startendself-startself-endfirst baselinelast baselinesafeunsafe:含义与兼容限制与 align-items 的其余取值相同。旧版 Safari、IE11 不支持。

image-20200613154244372

弹性项目尺寸的计算

最终主轴尺寸是三层一起算的结果:

  • 基础尺寸flex-basis、主轴方向的 widthheight、内容尺寸、box-sizing
  • 弹性增长或收缩flex-growflex-shrink
  • 最大最小限制min-widthmax-width(或对应的 height),以及内容最小尺寸。
最大最小尺寸限制 > 弹性增长或收缩 > 基础尺寸

计算顺序

  • 未设置 flex-basis 时,基准等于主轴方向的 width(或 height)。
  • flex-basiswidth 都未设置时,基准等于内容尺寸。
  • 默认 min-width: auto(主轴水平时),项目不会收缩到比内容最小尺寸更小。要比内容尺寸更小,设置 min-width: 0,或让该项目的 overflow 不为 visible
  • 主轴有剩余空间走 flex-grow;空间不足走 flex-shrink

text-overflow: ellipsis 失效

弹性项目里写了 text-overflow: ellipsis,省略号经常不出现:

<section>
    <div class="item">低眉含笑间</div>
    <div class="item">
        <div class="ellipsis">
            寒灯纸上梨花雨凉 谁的深情绚烂了三生石上的一见倾心 灯烛依旧 无人执手。低眉含笑间 寒灯纸上梨花雨凉 谁的深情绚烂了三生石上的一见倾心 灯烛依旧 无人执手
        </div>
    </div>
</section>
section {
    display: flex;
    width: 800px;
    margin: 0 auto;
    padding: 10px;
    border: 1px solid #0aa;
}

.item {
    padding: 10px;
    color: #fff;
    text-align: center;
    background-color: #0aa;
    white-space: nowrap;
}

.item:not(:last-child) {
    margin-right: 15px;
}

.ellipsis {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

image-20260817210857059

text-overflow: ellipsis 生效要同时满足:

  • white-space: nowrap:强制不换行;
  • overflow: hidden:溢出隐藏;
  • text-overflow: ellipsis:显示省略号;
  • 盒子的宽度必须小于文本固有宽度,内容才能溢出。

.ellipsis 写死一个比文本更小的 width 能让省略号显示,但不适合响应式。真正卡住的是弹性项目:默认 min-width: auto 把下限钉在内容最小尺寸上;内部 .ellipsis 又是 white-space: nowrap,内容最小尺寸就是整段文字的宽度。

结果是:

弹性项目的宽度 = `.ellipsis` 的宽度 = 文本内容宽度。文本没有溢出,ellipsis 不触发。

三种解决方案(作用在弹性项目上,不是作用在 .ellipsis 上):

  • 设置 overflow 不为 visible:自动最小尺寸按 0 处理,项目可以被收到容器分给它的可用宽度以内。
  • 设置 flex: 1; width: 0:主轴尺寸不按内容固有宽度起算,最终宽度仍由 flex 算法和 min、max 一起算。
  • 设置 min-width: 0:普通元素的 min-width 初始值是 0,弹性项目改成 auto,以免默认把内容挤没。写成 0 就是把自动下限关掉。宽度按 min(max(最小宽度, 可用宽度), 首选宽度) 计算。
<div class="item" style="overflow: hidden;">...</div>
<div class="item" style="flex: 1; width: 0;">...</div>
<div class="item" style="min-width: 0;">...</div>

文本自动省略 - DEMO

参考链接

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-08-18 22:07:38

results matching ""

    No results matching ""