CSS 播客 - 第 10 集:Flexbox
在自适应设计中,边栏与某些内容内嵌在一起是一种比较棘手的设计模式。在视口空间充裕的情况下,这种模式非常适用,但在空间较为紧凑的情况下,这种刚性布局可能会出现问题。
柔性框布局模型 (flexbox) 是专为一维内容设计的布局模型。 它擅于获取大量不同大小的项,并为这些项返回最佳布局。
这是此边栏模式的理想布局模型。Flexbox 不仅有助于内嵌排列边栏和内容,而且当剩余空间不足时,边栏会另起一行。使用 Flexbox 时,您可以提供灵活的边界来提示内容的显示方式,而不是为浏览器设置严格的尺寸。
您可以使用 Flex 布局执行哪些操作?
Flex 布局具有以下特性,您可以在本指南中探索这些特性。
- 它们可以显示为行或列。
- 它们遵循文档的书写模式。
- 它们默认是单行,但可以要求换行显示。
- 布局中的项在视觉上可以重新排序,与它们在 DOM 中的顺序不同。
- 空间可以分布在各项内容中,以便它们根据其父项中的可用空间变大或变小。
- 您可以使用 Box Alignment 属性在换行布局中围绕内容和 Flex 行分配空间。
- 内容本身可以在交叉轴上对齐。
主轴和交叉轴
了解 Flexbox 的关键在于了解主轴和交叉轴的概念。主轴是指由 flex-direction
属性设置的轴。如果该值为 row
,则主轴沿行;如果该值为 column
,则主轴沿列。
Flex 内容会在主轴上作为一个群组移动。 请注意:我们有许多内容,并且正在尝试为它们找到最佳布局。
交叉轴沿与主轴相反的方向延伸,因此如果 flex-direction
为 row
,交叉轴将沿着列延伸。
您可以在交叉轴上执行两项操作。您可以单独移动这些项或作为一组移动,使它们彼此对齐,并且与 flex 容器对齐。此外,如果您有封装的 Flex 行,则可以将这些行视为一个组,以控制为这些行分配空间的方式。在本指南的后续部分,您将了解所有这些在实践中的运作方式,现在只需记住主轴会跟随 flex-direction
即可。
创建 flex 容器
我们来看看 Flexbox 的行为方式,为此,我们将一组不同大小的项取出,并使用 Flexbox 对其进行布局。
<div class="container" id="container">
<div>One</div>
<div>Item two</div>
<div>The item we will refer to as three</div>
</div>
如需使用 Flexbox,您需要声明要使用 Flex 格式上下文,而不是常规的块级和内嵌布局。为此,请将 display
属性的值更改为 flex
。
.container {
display: flex;
}
如您在布局指南中所学,这将为您提供一个包含 flex 项子项的块级盒子。弹性项会立即开始使用其初始值来呈现一些 Flexbox 行为。
初始值的含义如下:
- 各项内容会显示为一行。
- 不换行。
- 它们不会变大来填满容器。
- 它们在容器的开头处对齐。
控制项的方向
即使您尚未添加 flex-direction
属性,这些项也会显示为一行,因为 flex-direction
的初始值为 row
。如果您想要显示行,则无需添加该属性。如需更改方向,请添加该属性和以下四个值之一:
row
:项排列成行。row-reverse:
项从 Flex 容器的末尾开始以行排列。column
:项以列的形式排列。column-reverse
:项从 Flex 容器的末尾开始以列的形式排列。
您可以在下面的演示中使用我们的一组项试用所有值。
反转项和无障碍功能的流程
使用任何会使视觉显示顺序与 HTML 文档中的顺序不一致的属性时,都应谨慎小心,因为这可能会对无障碍功能产生负面影响。row-reverse
和 column-reverse
值就是一个很好的例子。重新排序仅适用于视觉顺序,而非逻辑顺序。请务必了解这一点,因为逻辑顺序是屏幕阅读器读出内容的顺序,也是使用键盘导航的用户遵循的顺序。
通过以下视频可以看出,在反向行布局中,当键盘导航遵循 DOM(而非视觉显示)时,链接之间的 Tab 键会断开连接。
任何可以更改 Flexbox 或网格中项顺序的操作都可能会导致此问题。因此,任何重新排序都应包括全面的测试,以确保您的网站不会使某些用户难以使用。
如需了解详情,请参阅以下内容:
书写模式和方向
Flex 内容默认以行排列。 行是按照写作模式和脚本方向流动的句子的方向排列的。这意味着,如果您使用的是从右到左 (rtl) 脚本方向的阿拉伯语,这些项将在右侧对齐。由于阿拉伯语句子的阅读方式是从右到左,因此 Tab 顺序也会从右侧开始。
如果您使用的是垂直书写模式(例如某些日语字体),则一行将由上到下垂直运行。尝试更改此演示中使用纵向书写模式的 flex-direction
。
因此,默认情况下,Flex 项的行为方式与文档的写入模式相关联。大多数教程都是使用英语或其他水平(从左到右)书写模式编写的。这样,我们就可以轻松假定 flex 项会在左侧对齐并水平排列。
结合主轴和横轴以及书写模式来考虑,我们在 Flexbox 中讨论 start 和 end 而不是顶部、底部、左侧和右侧这一事实可能更易于理解。每个轴都有开始和结束。主轴的起点称为 main-start。因此,我们的 Flex 项目最初会从 main-start 排列。该轴的终点是 main-end。交叉轴的起点为 cross-start,终点为 cross-end。
换行 flex 项
flex-wrap
属性的初始值为 nowrap
。这意味着,如果容器中没有足够的空间,则项将溢出。
使用初始值显示的项会尽可能缩小,在溢出发生之前缩小到 min-content
大小。
如需使项封装,请向 flex 容器添加 flex-wrap: wrap
。
.container {
display: flex;
flex-wrap: wrap;
}
当 Flex 容器封装时,它会创建多个 Flex 行。在空间分配方面,每行都像一个新的 Flex 容器。因此,如果您换行,则无法让第 2 行的内容与第 1 行上方的内容对齐。这就是 flexbox 是一维的意思。 您可以控制一个轴(行或列)中的对齐方式,但不能同时控制这两个轴(就像在网格中一样)。
flex-flow 简写法
您可以使用缩写形式 flex-flow
设置 flex-direction
和 flex-wrap
属性。例如,如需将 flex-direction
设置为 column
并允许内容换行,请使用以下代码:
.container {
display: flex;
flex-flow: column wrap;
}
控制 Flex 项内的空间
假设容器的空间比显示项所需的空间多,则项会从一开始就排列整齐,而不会扩大以填充空间。它们会在达到最大内容大小时停止增长。这是因为 flex-
属性的初始值为:
flex-grow: 0
:内容不会增长。flex-shrink: 1
:项可以缩小到小于其flex-basis
的尺寸。flex-basis: auto
:项的基本大小为auto
。
这可以由关键字值 flex: initial
表示。flex
缩写属性或 flex-grow
、flex-shrink
和 flex-basis
的长格式会应用于 Flex 容器的子元素。
如需让项增大,同时允许大项比小项占用更多空间,请使用 flex:auto
。您可以使用上面的演示进行尝试。这会将属性设置为:
flex-grow: 1
:项可以超出其flex-basis
。flex-shrink: 1
:项可以缩小到其flex-basis
以下。flex-basis: auto
:项的基准大小为auto
。
使用 flex: auto
意味着项最终会采用不同的大小,因为各个项之间共享的空间是在每个项以最大内容大小进行布局后共享的。大型内容将会占据更多空间。
如需强制所有项的大小保持一致,并忽略内容的大小,请在演示中将 flex:auto
更改为 flex: 1
。
这会解压缩到:
flex-grow: 1
:项可以超出其flex-basis
。flex-shrink: 1
:项可以缩小到其flex-basis
以下。flex-basis: 0
:项的基本大小为0
。
使用 flex: 1
表示所有项的大小均为零,因此 Flex 容器中的所有空间都可以分配。由于所有项的 flex-grow
系数均为 1
,因此它们都会均匀扩大,并且空间也会均等共享。
允许不同项以不同的速率成长
您不必为所有项都设置 1
的 flex-grow
系数。您可以为 Flex 项指定不同的 flex-grow
系数。在下面的演示中,第一项具有 flex: 1
、第二个 flex: 2
和第三个 flex: 3
。随着这些项从 0
开始增长,Flex 容器中的可用空间会被分成 6 份。第一个项获得 1 份,第二个项获得 2 份,第三个项获得 3 份。
您可以通过 auto
的 flex-basis
执行相同的操作,但您需要指定这三个值。第一个值为 flex-grow
,第二个值为 flex-shrink
,第三个值为 flex-basis
。
.item1 {
flex: 1 1 auto;
}
.item2 {
flex: 2 1 auto;
}
这是一种不太常见的用例,因为使用 auto
的 flex-basis
是为了让浏览器能够确定空间分布。不过,如果您希望某个商品的展示次数比算法决定的略多一些,则该参数可能很有用。
重新排列 Flex 项
可以使用 order
属性对 Flex 容器中的项进行重新排序。此属性允许对序数组中的项进行排序。项会按 flex-direction
指定的方向排列,值越低越先排列。如果有多个项具有相同的值,则该值将与具有该值的其他项一起显示。
以下示例演示了这种排序。
检查您的理解情况
测试您对 Flexbox 的了解程度
默认 flex-direction
为
row
column
默认情况下,Flex 容器封装了子节点。
flex-wrap: wrap
与 display: flex
搭配使用以封装子项Flex 子项显示为挤压,下面哪个 Flex 属性有助于缓解这种情况?
flex-grow
flex-shrink
flex-basis
Flexbox 对齐概览
Flexbox 自带一组属性,可用于对齐项目和分配项目之间的空间。这些属性非常有用,它们已被纳入各自的规范,您在网格布局中也会遇到它们。您可以在此处了解在使用 Flexbox 时这些属性的运作方式。
这组房源可以分为两组。用于分配空间的属性和用于对齐的属性。 分配空间的属性包括:
justify-content
:主轴上的空间分布。align-content
:交叉轴上的空间分布。place-content
:用于设置上述两个属性的简写形式。
Flexbox 中用于对齐的属性:
align-self
:在横轴上对齐单个项。align-items
:将所有项作为一个组在横轴上对齐。
如果您处理主轴,则属性以 justify-
开头。在交叉轴上,它们以 align-
开头。
在主轴上分配空间
使用前面使用的 HTML 时,Flex 项会以行排列,主轴上会留有空白。项的大小不足以完全填满 flex 容器。
这些项会在 Flex 容器的开头排列,因为 justify-content
的初始值为 flex-start
。这些项在开头排列,任何多余的空格都位于末尾。
将 justify-content
属性添加到 Flex 容器,将其值设为 flex-end
,项目在容器末尾排队,空闲空间位于起始位置。
.container {
display: flex;
justify-content: flex-end;
}
您还可以使用 justify-content: space-between
在项之间分配空间。
请尝试在演示中使用一些值,并参阅 MDN 了解完整的可能值集。
活动门票提供商:flex-direction: column
如果您已将 flex-direction
更改为 column
,则 justify-content
将适用于该列。若要让容器在作为列时有空余空间,您需要为容器提供 height
或 block-size
。否则,您将没有可用于分发的空间。
这次,尝试使用不同的值,并采用 Flexbox 列布局。
在柔性线条之间分配空间
使用经过封装的 flex 容器时,您可能有空间在交叉轴上进行分布。在这种情况下,您可以使用与 justify-content
相同值的 align-content
属性。与默认将项与 flex-start
对齐的 justify-content
不同,align-content
的初始值为 stretch
。将 align-content
属性添加到 flex 容器,以更改此默认行为。
.container {
align-content: center;
}
在演示中试用一下。
该示例包含换行 Flex 项,并且容器包含 block-size
,以便我们留出一些空白。
place-content
简写法
如需同时设置 justify-content
和 align-content
,您可以将 place-content
与一个或两个值搭配使用。如果您同时指定这两个值,则第一个值用于 align-content
,第二个值用于 justify-content
,这两个轴将使用相同的值。
.container {
place-content: space-between;
/* sets both to space-between */
}
.container {
place-content: center flex-end;
/* wrapped lines on the cross axis are centered,
on the main axis items are aligned to the end of the flex container */
}
对齐交叉轴上的项
在横轴上,您还可以使用 align-items
和 align-self
在 flex 行中对齐项。可用于此对齐方式的空间取决于 Flex 容器的高度,或者在内容已换行的情况下,取决于 Flex 行。
align-self
的初始值为 stretch
,因此,默认情况下,一行中的 flex 项会延伸到最高项的高度。如需更改此设置,请将 align-self
属性添加到任何 Flex 项。
.container {
display: flex;
}
.item1 {
align-self: flex-start;
}
使用以下任一值对项进行对齐:
flex-start
flex-end
center
stretch
baseline
请参阅 MDN 上完整的值列表。
下一个演示包含一行包含 flex-direction: row
的 Flex 项。最后一个项定义了 flex 容器的高度。第一个项的 align-self
属性值为 flex-start
。请尝试更改该属性的值,看看它在横轴上的空间内如何移动。
align-self
属性会应用于各个项。可以将 align-items
属性应用于 Flex 容器,将所有单独的 align-self
属性设为一个组。
.container {
display: flex;
align-items: flex-start;
}
在下一个演示中,请尝试更改 align-items
的值,以将交叉轴上的所有项作为一个组对齐。
为什么 Flexbox 中没有“ Justify-self”?
Flex 内容在主轴上作为一个组。 因此,没有从该组中拆分个别项的概念。
在网格布局中,justify-self
和 justify-items
属性会在内嵌轴上运行,以便在网格区域内对该轴上的项进行对齐。由于 Flex 布局将项视为组,因此这些属性不会在 Flex 上下文中实现。
值得注意的是,flexbox 确实可以与自动边距搭配使用。如果您需要从组中拆分一项,或需要将该组拆分为两组,则可以使用外边距来执行此操作。在以下示例中,最后一个项的左边距为 auto
。自动边距会吸收应用方向上的所有空间。这意味着,它会将项推向右侧,从而拆分组。
如何垂直和水平居中显示内容
对齐方式属性可用于将项居中放置在另一个框中。justify-content
属性用于对齐主轴(即行)上的项。交叉轴上的 align-items
属性。
.container {
width: 400px;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
}
检查您的理解情况
测试您对 Flexbox 的了解程度
.container { display: flex; direction: ltr; }
要与 Flexbox 垂直对齐,请使用
.container { display: flex; direction: ltr; }
如需使用 Flexbox 进行水平对齐,请使用
.container { display: flex; direction: ltr; }
默认情况下,Flex 项会对齐到 stretch
。如果要将内容大小用于子项,您会使用以下哪种样式?
justify-content: flex-start
align-content: start
content
用于对齐 flex 行,而不是对齐子项。height: auto
align-items: flex-start