CSS: Layout: Flexbox

21st May 2021 at 1:18am
CSS: Layout

现在(2019)主流的 CSS 框架都使用的 Flexbox。比如 Bulma 的 column 系统。

Core

Flexbox 是在一个维度上排列项目的排版方式。Grid 提供了在两个维度上的排版方式。

Flexbox 的模型大概如图,由一个 容器(box / container) 包含着若干个 项目(item)

它有一个主轴(main axis,在上图中是 row),表明它是横向排列项目还是纵向,以及项目默认排列方向,比如从左向右还是从右往左。还有一个交叉轴(cross axis),与主轴成交叉。

Flexbox 有几个核心问题要解决:

  • 一个盒子的轴(axis)是什么。轴代表了 box 中项目的排列方向,可横着排也可竖着排(flex-directionflex-wrap 以及 flex-flow shoutcut)
  • 项目占用的空间是多少;如果盒子剩余空间过多或者不够,项目的占用空间应该怎样调整、是否要换行(flex-basisflex-grow 以及 flex-shrink
  • 项目在主轴上应该怎样分布,是都挤在左边还是往两边散开(justify-content);在交叉轴上应该怎样分布(align-itemsalign-self
  • 当发生换行并且存在多行时,各行处在容器的什么位置上(align-content

容器的 display 需要设置成 flex

上面提到的 CSS 属性中:

  • 用在容器上:flex-directionflex-wrapflex-flow
  • 用在项目上:flex-basisflex-growflex-shrinkalign-self
  • 同时可用:
    • justify-content:用在容器上表示项目的排列;用在项目上时表示项目内容的排列
    • align-items:同 justify-content,区别在于 justify-content 处理 main axis,而 align-items 处理 cross axis

flex 是这三者的 short hand:flex-grow, flex-shrink, flex-basis

flex-basis

这篇 文章 给出了很好的解答。

简单来说,一个 flex item 在 grow / shrink 之前的宽度/高度判定是这样的:

  1. 如果设置了 flex-basis,优先用它,否则:
  2. 如果设置了 width 或者 height,优先用它,否则:
  3. 根据其内容多少来判定

不管用哪个属性,它们都遵循 max-width / min-width(或其 height 版本)所带来的约束。

常见用法

Tailwind CSS 描述了一些 常见用法

Bulma 分栏系统实现

对于未指定宽度的栏,Bulma 默认都使用这样的属性,让它们自动分配大小:

flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;

当有一些栏指定了宽度比例(比如 is-four-fifths)时,Bulma 采用百分比(如 80%)作为其宽度值并置 flex: none (即 flex: 0 0 auto)使其不会自动扩缩。

为了让不同栏之间的距离合理,应该:

  • 使用 border-boxbox-sizing 使宽度计算中包含 borderpadding
  • 栏之间的空白应该使用 padding 而不是 margin,因为 margin 不包含在 border-box

Resources