原文链接:Everything You Need To Know About Alignment In Flexbox, by Rachel Andrew
在 本系列的第一篇文章 中,我解释了当在元素上声明 display: flex
的时候,发生了什么。这一次我将带领大家浏览一下对齐属性(alignment properties),看看它们是如何在 Flexbox 中起作用的。如果你曾困惑不知道该使用 align-*
属性还是 justify-*
属性的话,我希望本文能够帮你解决这个困惑。
Flexbox 对齐属性简史
在整个 CSS 布局历史中,如何能自如地在两个轴上对齐元素可能是 Web 设计领域的最让人头大的问题了。因此第一次看见 Flexbox 中对齐项目的功能时,是非常令人兴奋的。比如,下面两行 CSS 便能轻松做到居中对齐:
See the Pen Smashing Flexbox Series 2: center an item by Rachel Andrew
你可能认为这些属性仅是作为 Flexbox 布局中的对齐属性使用的,事实上不是,这些属性现在都定义在了 Box Alignment 规范 中。这个规范描述了这些对齐属性是如何在不同的布局上下文(layout contexts)中起作用的。也就是说,我们可以在 CSS 网格(Grid)中使用在弹性布局中用到的这些对齐属性——当然,未来可能还会有其他的布局上下文出现。因此,未来 Flexbox 中新的对齐功能将会在 Box Alignment 规范中定义,而不是在 Flexbox 规范中。
属性
许多人跟我说在使用 Flexbox 过程中,很容易被“这里该使用 align-
属性还是 justify
属性?”的问题搞懵圈。这里告诉你一个简单的记忆方法:
justify-
操作的是主轴(main axis)对齐,对齐方向与flex-direction
方向一致。align-
操作的是交叉轴(cross axis)对齐,对齐方向与flex-direction
方向垂直。
这里我们使用的是“主轴”和“交叉轴”,而没有说“水平方向”或“垂直方向”,是因为前者(两根轴)的方向跟物理方向并不是关联的。
主轴对齐:justify-content
我们从主轴对齐开始讲起。在主轴上对齐,我们使用的是 justify-content
属性。这个属性把所有的 Flex 项目当成一组,控制项目之间的空间分配。
justify-content
的初始值是 flex-start
。这就是为什么,在声明 display: flex
之后,所有的 Flex 项目都是在弹性线(flex line) 的起始处对齐的。当 flex-direction
是 row
且处于从左到右的语言环境的时候(比如英语),这个起始处就位于左边。
Flex 项目在起始处对齐
需要注意的是,justify-content
仅在有剩余空间可供分配的情况下才起作用。如果在主轴上,Flex 项目分配完毕后,已无可供分配的剩余空间,justify-content
不会起任何作用。
无空间可供分配
如果我们给 justify-content
使用的是 flex-end
,那么所有项目都是在弹性线末尾对齐,剩余空间位于头部。
Flex 项目在末尾处对齐
剩余空间的分配还有更多方式。比如,我们可以空间在 Flex 项目之间平均分配,需要用到 justify-content: space-between
。这种情况下,第一个和最后一个 Flex 项目会靠在容器边缘,然后剩余空间会在项目之间均等分配。
剩余空间在项目之间平均分配
也可以使用 ustify-content: space-around
。这种情况下,剩余空间会在每个项目的两边分配。
剩余空间在每个项目的两边分配
译注:因为每个项目两边都分到了一样的空间。因此,项目间的间距会是项目与容器边缘间距的两倍。图中的容器设置了
padding
值,因此看出的效果可能没那么明显,在此告知大家。
Box Alignment 规范还为 justify-content
属性定义了一个新值 space-evenly
,它并未出现在 Flexbox 规范中。使用了这个值后,项目与容器之间、项目与项目之间的分配的空间大小是一样的。
项目均匀分布于容器内
下面的 demo 展示了在不同取值情况下的项目分配:
See the Pen Smashing Flexbox Series 2: justify-content with flex-direction: row by Rachel Andrew
flex-direction
取值 column
的时候,这些值的作用效果是一样的。当然了,除非你给 Flex 容器一个高度或者容器本身是 block-size 的,否则是没有额外空间可供非配的。请看下面的 demo:
See the Pen Smashing Flexbox Series 2: justify-content with flex-direction: column by Rachel Andrew
交叉轴对齐:align-content
如果 Flex 容器使用了 flex-wrap: wrap
,我们就能得到多行(multiple flex lines)
显示的 Flex 项目,align-content
就是处理在交叉轴上行之间的剩余空间分配。当然,前提是在交叉轴上存在剩余空间可供分配。在下面的例子中,交叉轴以列的形式在块方向(block direction)上布局,我把容器的高度设置为 60vh
了,这比 Flex 项目所需要的空间要多,这样我们就有空间在垂直方向上进行分配了。
我们可以使用下图里列举的值,布局交叉轴上的对齐:
See the Pen Smashing Flexbox Series 2: align-content with flex-direction: row by Rachel Andrew
如果 flex-direction
取值 column
,则 align-content
将按如下方式布局:
See the Pen Smashing Flexbox Series 2: align-content with flex-direction: column by Rachel Andrew
类似于 justify-content
,align-content
是把多行看成一个组来分配剩余空间的。
简写属性:place-content
阅读 Box Alignment 规范,发现有一个简写属性 place-content
,这个属性是 justify-content
属性和 align-content
属性的简写形式。place-content
接收两个值,第一个值指定 align-content
,第二个值指定 justify-content
;如果只指定一个值的话,两个属性都设置为这个值。因此:
.container {
place-content: space-between stretch;
}
/* 等效于 */
.container {
align-content: space-between;
justify-content: stretch;
}
/* 如果是这样使用的 */
.container {
place-content: space-between;
}
/* 则等效于 */
.container {
align-content: space-between;
justify-content: space-between;
}
交叉轴对齐:align-items
我们已经知道,可以将一组 Flex 项目或将多行弹性线(flex lines)作为组进行对齐。但是还有一个小小的需求,就是希望在交叉轴上以彼此关联的方式对 Flex 项目做对齐。Flex 容器会有一个高度,这个高度可能是由最高的那个 Flex 项目决定的。
容器的高度是由第三个项目的高度决定的
当然,也可以直接给 Flex 容器一个高度:
直接在容器上定义了高度
其他 Flex 项目之所以会伸展与最高项一样的高度,是因为 align-items
属性的初始值是 stretch
。项目在交叉轴上伸展,直到尺寸和 Flex 容器的尺寸一样。
我们要注意到 align-items
的作用点是哪里。对于多行 Flex 容器,每一行都像是一个新的 Flex 容器,那一行里最高的 Flex 项目将决定改行其他项目的高度。
除了初始值 stretch
,还可以使用 flex-start
,此属性会让 Flex 项目沿着容器的起点处对齐,不会伸展到与容器一样的高度了。
Flex 项目沿着交叉轴的起点处对齐
而 flex-end
则让 Flex 项目沿着交叉轴的终点处对齐。
Flex 项目沿着交叉轴的终点处对齐
如果使用的是 center
,则所有项目的沿着中心对齐。
在交叉轴上居中对齐项目
还可以基于基线对齐。与上面的基于项目中心线对齐不同,这是根据文本的基线对齐的:
基线对齐
可以查看下图,发现不同值产生的效果:
See the Pen Smashing Flexbox Series 2: align-items by Rachel Andrew
单个项目对齐:align-self
align-items
的意思是一次设置所有 Flex 项目的对齐方式。实际是把所有 Flex 项目的 align-self
属性做了统一的设置。你也可以在单个 Flex 项目上使用 align-self
属性,指定在行(flex line)内与其它 Flex 项目不同的对齐方式。
在下例中,我们在 Flex 容器上将 align-items
属性设置为 center
,并且为第一个和最后一个项目分别指定了单独的对齐方式。
See the Pen Smashing Flexbox Series 2: align-self by Rachel Andrew
为什么没有 justify-self?
译注:
原文作者这里的解释有点牵强。详细可参考 stackoverflow 上的回答:In CSS Flexbox, why are there no “justify-items” and “justify-self” properties?。
总结下来的话,就是没有必要,因为使用下面即将要说的 auto margin 方案就能解决。规范中也是介绍使用 auto margin 解决主轴上部分项目的个性化对齐问题的。
一个常见的问题是,如何在主轴对齐一个项目或者一组项目。为什么 Flexbox 主轴上没有 -self
属性?如果你知道 justify-content
和 align-content
是用来分配剩余空间的,那么可能就能搞懂为什么没有 self-alignment 属性了。我们把 Flex 项目看成一组,并对可用空间进行分配——在组的头部或者尾部或者再项目之间。
我们可以思考下 justify-content
和 align-content
属性在 CSS Grid 布局中的作用。这两个属性在 Grid 中是用来分配*网格轨迹之间(between grid tracks)*的间距的。它们把轨迹看成是一个组,这些属性就是用来分配这些轨迹之间的间距的。由于我们同时在 Grid 和 Flexbox 中对一个组进行操作,因此我们不能单独针对一个项目来做一些不同的事情。然而,有一种方法可以实现当您在主轴上请求 self
属性时所要求的那种布局,那就是使用 auto margin。
在主轴上使用 auto margin
如果你有过用 CSS 居中显示一个块元素的经验(通过给内容页设置左右 margin
为 auto
),你就已经理解 auto margin 实现居中的行为。如果我们设置了一个方向上的 margin: auto
,那么这个 margin
会尽可能的占据该方向的空间大小。在使用 margin
居中块元素的例子中,我们将左右 margin
都设置为了 auto
,它们每个都尽可能的争夺空间,最终将块元素推倒了中间的位置。
auto margin 在主轴对齐上同样表现优秀,它可以实现单个项目或者一组项目的对齐。下例中,我实现了一个常见的设计模式——我使用 Flexbox 实现了一个导航栏,项目显示为一行,使用了初始值 justify-content: start
。我想让最后一个项目显示在弹性线(flex line)的末尾(当然,前提假设是这一行上有足够的空间)。
我选中了这个项目,并且给了它 margin-left: auto
。这就是说项目的左边会占据尽可能多的空间,也就是说这个项目会被推倒了右边。
See the Pen Smashing Flexbox Series 2: alignment with auto margins by Rachel Andrew
如果在主轴上使用了 auto margin,justify-content
就会失去效果,因为 auto margin 会占据所有本来要给 justify-content
分配的空间。
回退对齐
每个对齐方法都有一个详细的回退对齐,这是在请求的对齐不能实现的情况下发生的事。例如,如果在容器中只有一个项目,并且使用了 justify-content: space-between
,那么结果如何?答案是会使用回退对齐 flex-start
,然后发现这个项目在 Flex 容器的起点处对齐了;对 justify-conrtent: space-around
的情况,回退对齐是 center
。
当前规范中,我们还无法修改回退对齐,如果你想让 space-between
的回退方案采用 center
而非 flex-start
的话,是做不到的。 规范中有一个 Note 提到未来的版本中可能会支持。
Safe 和 Unsafe 对齐
Box Alignment 规范最近新增了 Safe 和 Unsafe 对齐的概念,对应关键字 safe
和 unsafe
。
下面的代码中,最后一项对于 Flex 容器来说太宽了,且对齐方式不安全。Flex 容器位于页面左侧,当溢出超出页面边界时,发现这一项被切断了。
.container {
display: flex;
flex-direction: column;
width: 100px;
align-items: unsafe center;
}
.item:last-child {
width: 200px;
}
不安全的对齐方式导致的对齐结果可能导致数据丢失
而安全对齐方式会避免数据丢失的出现,将溢出转移到另一边。
.container {
display: flex;
flex-direction: column;
width: 100px;
align-items: safe center;
}
.item:last-child {
width: 200px;
}
安全对齐避免数据丢失
See the Pen Smashing Flexbox Series 2: safe or unsafe alignment by Rachel Andrew
总结
对齐属性起源于 Flexbox,但是现在位于独立的规范中,并可用于其他布局上下文中。以下几个关键事实将帮助你记住如何在 Flexbox 中使用它们:
justify-
主轴对齐,align-
交叉轴对齐;- 使用
align-content
和justify-content
属性时需要有额外的剩余空间; align-content
和justify-content
属性把 Flex 项目看成一组来处理。因此对这些属性而言,没有针对单个项目的-self
对齐属性。- 如果你希望在主轴上对齐一个项目,或者把部分项目作为一组对齐的话,可以使用 auto margin。
align-items
用于统一设置 Flex 项目上的align-self
属性。在 Flex 项目上使用align-self
用于单独设置此项目的对齐方式。
(完)