我们曾如此渴望命运的波澜,到最后才发现,人生最曼妙的风景,竟是内心的淡定和从容。我们曾如此期盼外界的认可,到最后才知道,世界是自己的,与他人毫无关系。——杨绛
网页布局(layout)的传统解决方案,
基于盒状模型,依赖 display属性 + position属性 + float属性。
它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。
44年前我们把人送上月球,但在CSS中我们仍然不能很好实现垂直居中。
——James Anderson
2009年,W3C提出了一种新的方案——Flex布局,可以简便、完整、响应式地实现各种页面布局。
Flex是Flexible Box的缩写,即“弹性盒子”,用来为盒状(盒子)模型提供最大的灵活性。
Flexible(灵活的; 有弹性的; 可变动的;)
弹性盒子是一种用于按行或按列布局元素的一维布局方法; 元素可以膨胀以填充额外的空间, 也可收缩以适应更小的空间;
使用Flexible Box来进行布局的方案称之为Flex布局(Flex layout)。
目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
——(两对象,两轴,两线,两尺寸)
Basics and terminology(基础知识和术语)
Since flexbox is a whole module and not a single property, it involves a lot of things including its whole set of properties. Some of them are meant to be set on the container (parent element, known as “flex container”) whereas the others are meant to be set on the children (said “flex items”).
If “regular” layout is based on both block and inline flow directions, the flex layout is based on “flex-flow directions”. Please have a look at this figure from the specification, explaining the main idea behind the flex layout.
由于flexbox是一个完整的模块(css3以模块的形式更新版本),而不是一个单独的属性,所以它涉及到很多事情,包括它的一整套属性。其中一些要设置在容器上(父元素,称为“弹性容器”),而另一些则要设置在子元素上(称为“弹性项目”)。
“常规”布局基于块流方向(垂直方向)和内联流方向(水平方向),而弹性布局则基于“弹性流方向”。请看一下本说明书中的这个图(下图),其解释着flex布局背后的主要思想。
两对象:flex container(容器)和 flex item(项目)
两轴:main axis(主轴) 和 cross axis(交叉轴)
两线:main/cross start (起始线)和 main/cross end (终点线)
两尺寸: main size(主尺寸) 和 cross size (交叉尺寸)
Items will be laid out following either the
main axis
(frommain-start
tomain-end
) or the cross axis (fromcross-start
tocross-end
).项目将按照主轴(从主起始线main start到主终点线main end)或交叉轴(从交叉起始线cross start到交叉终点线cross end)进行布置。
- main axis 主轴 – The main axis of a flex container is the primary(首要的、最重要的) axis along which flex items are laid out. Beware, it is not necessarily horizontal; it depends on the
flex-direction
property (see below).- ——弹性容器的主轴是布置弹性项目的首要的轴。小心,它(主轴)不一定是水平的;它取决于flex direction属性(见下文)。
- main-start | main-end 主起始线和主终点线 – The flex items are placed within the container starting from main-start and going to main-end.
- ——弹性项目被放置在容器内,从主起始线一直到主终点线。
- main size 主尺寸 – A flex item’s width or height, whichever is in the main dimension(尺寸; 方面; 范围), is the item’s main size. The flex item’s main size property is either the ‘width’ or ‘height’ property, whichever is in the main dimension.
- ——弹性项目的宽度或高度(以主尺寸中的宽度或高度为准)是项目的主尺寸。弹性项的主要大小属性是“width”或“height”属性,以主维度中的属性为准。简而言之(项目默认沿主轴排列。单个项目占据的主轴空间叫做main size)
- cross axis 交叉轴 – The axis perpendicular to the main axis is called the cross axis. Its direction depends on the main axis direction.
- ——垂直于主轴的轴称为交叉轴。其方向取决于主轴方向。
- cross-start | cross-end 交叉起始线和交叉终点线 – Flex lines are filled with items and placed into the container starting on the cross-start side of the flex container and going toward the cross-end side.
- ——弹性行 装着满满的项目,并从弹性容器的交叉起始线开始放置到容器中,然后向交叉端侧移动。
- cross size 交叉尺寸 – The width or height of a flex item, whichever is in the cross dimension, is the item’s cross size. The cross size property is whichever of ‘width’ or ‘height’ that is in the cross dimension.
- 弹性项目的宽度或高度,以交叉尺寸中的值为准,即为项目的交叉尺寸。cross-size属性是cross-dimension中的“width”或“height”中的任意一个。简而言之(占据的交叉轴空间叫做cross size。)
display属性可以定义一个弹性容器;内联或块,取决于给定的值。它为其所有直接子项目启用了灵活的上下文。
请注意,CSS列对flex容器没有影响。
display: flex; 就是在告诉你的浏览器,“我想使用弹性盒子,在这个容器。”
属性值设置为flex和inline-flex的区别:
1.如果display对应的值是flex的话,
那么
flex container
是以block-level
的形式存在的,相当于是一个块级元素(块级元素占据其所在行的整个宽度)
2.如果display的值设置为
inline-flex
的话,那么
flex container
是以inline-level
的形式存在的,相当于是一个行内块元素3.这两个属性值差异的影响在设置了属性值的元素上面,它们在子元素上的效果都是一样的
4.如果一个元素的父元素开启了flex布局;
那么其子元素的display属性对自身的影响将会失效,但是对其内容的影响依旧存在的;
举个例子:父元素设置了
display: flex
,即使子元素设置了
display:block
或者display:inline
的属性,子元素还是会表现的像个行内块元素一样,这就是父元素对其的影响使其display属性对自身的影响失效了;
(父元素从
display:block转变为display: flex
)但是为什么我们说其对内容的影响还在呢?
假如说父子元素都设置了
display: flex
,那么子元素自身依然是行块级元素,并不会因为其开启了flex布局就变为块级元素,
但是该子元素的内容依然会受到它flex布局的影响,各种flex特有的属性就会生效;
总结:我们如果想让设置flex布局的盒子变成块级元素的话,那就dispaly的属性值就设置为flex;
如果想让盒子变为行内块元素的话,就设置为
inline-flex
;父元素开启了flex布局之后,子元素的display属性对元素本身的影响就会失效,但是依旧可以影响盒子内部的元素;
图示动画展示了flex-direction的四个可能值:从上到下、从下到上、从右到左和从左到右。
flex-direction属性将建立主轴,从而定义项目在容器中的放置方向。
Flexbox(除了可选的包装)是一个单向布局概念。
将弹性项目视为主要以水平行或垂直列的形式进行布局。
row
(default):在ltr中从左到右;rtl中从右到左
row-reverse
:在ltr中从右向左;rtl中从左到右
column
:与行相同,但从上到下
column-reverse
:与行反转相同,但自下而上
ltr ?rtl?
——书写模式(writing-mode)、文字方向性
writing-mode
属性指定块流动方向和行级内容的流动方向。CSS writing-mode属性
flex direction允许您控制容器中项目的显示方式。您希望它们从左到右、从右到左、从上到下还是从下到上?通过设置容器的dlex-direction,可以轻松地完成所有这些操作。
应用display:flex后的默认排列(flex-direction:row;)是沿主轴从左到右排列。下面的动画显示了将flex-direction:column; 添加到容器元素时发生的情况。
也可以将 flex-direction 设置为 column 和 column-reverse
默认情况下,弹性项目都会尝试放在一行一条线(“轴线”)上。
您可以在需要的时候,更改此属性,使项目换行。
nowrap(default):所有弹性项目都将在一行上。
wrap:弹性项目将从上到下换行成多行。
wrap-reverse:弹性项目将从下到上换行成多行。
这是 flex direction 和 flex wrap 属性的简写,它们共同定义了flex容器的主轴和横轴。
默认值为row nowrap。
justify-content 决定了 flex items 在 main axis 上的对齐方式
这定义了沿主轴的对齐方式。当一行中的所有弹性项目都是不灵活的,或者是灵活的但已达到最大大小时,它帮助分配剩余的额外可用空间。
当项目溢出行时,它还对项目的对齐进行一些控制。
flex-start(默认):项目朝(挤向)flex-direction的起始位置排列。
flex-end:项目朝(挤向)flex-direction的结束位置排列。
start:项目朝书写模式方向的起始位置排列。
end:项目朝书写模式方向的结束位置排列。
left:项目朝容器的左边缘排列,除非与flex-direction不符合,否则会表现得像start。
right:项目朝容器的右边缘排列,除非与flex-direction不符合,否则会表现得像end。
center:项目在行中居中对齐(挤在中间)。
space-between:项目在行中均匀分布;第一个项目在起始线上,最后一个项目在结束线上。
space-around:项目在行中均匀分布,并在它们周围有相等的空间。请注意,从视觉上看,空间并不相等,因为所有项目两侧的空间相等。第一个项目将在容器边缘有一个单位的空间,但是在下一个项目之间有两个单位的空间,因为下一个项目有自己的间距。
space-evenly:项目的间距(以及边缘的空间)均等分布。
请注意,对于这些值的浏览器支持是有差异的。
例如,某些版本的Edge从未支持space-between,
而start/end/left/right在Chrome中尚未支持。MDN有详细的图表可供参考。
最安全的值是flex-start、flex-end和center。
此外,还有两个额外的关键词可以与这些值配对使用:safe和unsafe。
使用safe可以确保无论如何进行这种定位类型,都不会将元素推到屏幕之外(例如顶部之外),以避免内容无法滚动(称为“数据丢失”)。
align-items 决定了 flex items 在 cross axis 上的对齐方式
这定义了在当前行上沿着交叉轴如何排列 flex 项目的默认行为。可以将其视为交叉轴(与主轴垂直)上的 justify-content 版本。
stretch(默认值):拉伸以填充容器(但仍要考虑最小宽度/最大宽度)
flex-start / start / self-start:项目放置在交叉轴的起始位置。它们之间的差异微小,与是否遵守 flex-direction 规则或书写模式规则有关。
flex-end / end / self-end:项目放置在交叉轴的结束位置。差异还是很小,与是遵守 flex-direction 规则还是书写模式规则有关。
center:项目在交叉轴上居中对齐
baseline:项目对齐以使它们的基线对齐
安全(safe)和不安全(unsafe)修饰符关键词可以与其余所有关键词结合使用(请注意浏览器支持情况),用于帮助您防止对齐元素导致内容变得不可访问。
justify-content和align-items居中
现在我们将同时使用justify-content和align-items属性。这将展示主轴和交叉轴之间的区别。
gap、row-gap和column-gap属性用于控制弹性项目之间的间距。它仅在项目之间应用该间距,而不应用于外边缘上的项目。
这个属性的表现可以被看作是一个最小的间隔,如果间隔更大(因为像justify-content: space-between;这样的属性),那么只有当空间变小时,间隔才会生效。
gap属性不仅适用于flexbox,还适用于grid布局和多列布局。
CSS中的gap属性是row-gap和column-gap的简写,用于指定网格、flex和多列布局中行和列之间的间距(gutters)的大小。
默认情况下,flex项目按照它们在源代码中的顺序进行布局。
然而,order属性可以控制它们在flex容器中的显示顺序。
具有相同order值的项将按照它们在源代码中的顺序进行布局。
可以设置任意整数(正整数、负整数、0),值越小就越排在前面
默认值是 0
flex-grow属性
(如图示例子)在这个例子中,有两行flex项目,第一行的所有项都是相等大小的,它们的flex-grow值也相等;而第二行的中间项的宽度是其他项的两倍,因为它的flex-grow值为2。
flex-grow属性定义了flex项在需要时的扩展能力。它接受一个无单位的值,用作比例。它决定了flex项在flex容器内可用空间中所占的比例。
如果所有项目的flex-grow值都设置为1,那么容器中剩余的空间将平均分配给所有子项。如果其中一个子项的值为2,那么该子项将占据其他子项中任意一个的两倍空间(至少会尝试如此)。
负数是无效的。
注意:flex items 扩展后的最终 size 不能超过 max-width\max-height
flex-shrink属性定义了flex项在需要时的收缩能力。
负数是无效的。
flex-basis 用来设置 flex items 在 main axis 方向上的 base size
这个属性定义了在 剩余空间分配之前 元素的默认大小。
它可以是一个长度值(例如20%,5rem等)或关键字。
关键字auto(默认)表示“根据我的宽度或高度属性来确定”(这个功能曾经被main-size关键字临时代替,但已被弃用)。
关键字content表示“根据项的内容来确定大小” - 这个关键字目前支持不太好,所以很难测试,并且更难知道它的兄弟关键字max-content、min-content和fit-content的作用。
如果设置为0,额外的空间不会被计算在内。
如果设置为auto,额外的空间将根据其flex-grow值进行分配。参考这个图示。
决定 flex items 最终 base size 的因素,从优先级高到低
max-width\max-height\min-width\min-height
flex-basis
width\height
内容本身的 size
flex是flex-grow、flex-shrink和flex-basis的简写形式。
第二个和第三个参数(flex-shrink和flex-basis)是可选的。
默认值是 0 1 auto,但如果您使用单个数字值设置它,例如 flex: 5; ,
那么 flex-basis 将变为 0%,就像设置了 flex-grow: 5; flex-shrink: 1; flex-basis: 0% 一样。
建议您使用这个简写属性而不是设置单独的属性。简写属性会智能地设置其他值。
图示:align-self属性用于将一个项目相对于flex容器的顶部而不是底部进行定位,这与其他所有项目的位置相反。
这允许为单个flex项目覆盖默认对齐方式(或由align-items指定的对齐方式)。
请参阅align-items的解释以了解可用的值。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
请注意,float、clear和vertical-align对flex项目没有影响。
align-self属性允许您调整单个元素的对齐方式。
它具有与align-items相同的属性。
在下面的动画中,父级div具有CSS属性align-items: center和flex-direction: row。
前两个方块循环显示不同的align-self值。
参考
A Complete Guide to Flexbox | CSS-Tricks - CSS-Tricks
Flexbox - The Ultimate CSS Flex Cheatsheet (with animated diagrams!)