flex布局
主轴与交叉轴
学习 flex 布局需要明白 主轴(main axis)和 交叉轴(cross axis)两个概念。首先采用了 flex 布局的元素被称为 "容器"(flex container),它的所有子元素都是容器的 "项目"(flex item),容器中存在两个轴:
- 水平的主轴(main axis),主轴开始位置叫 main start,结束位置叫 main end,默认情况下是 从左往右
- 垂直的交叉轴(cross axis),交叉轴开始位置 cross start,结束位置叫 cross end,默认情况下是 从上往下
如何成为 flex 容器
如果要让一个盒子成为 flex 容器,你需要调整其 display 属性:
display: flex
,盒子具有 容器级块元素 特点,并且成为了 flex 容器,可以使用 flex 容器所有属性display: inline-flex
,盒子具有 行内块元素 特点,并且成为了 flex 容器,可以使用 flex 容器所有属性
flex 容器中项目的特点
无论项目是 块级元素 还是 行内元素,在 flex 容器中,盒子模型的所有属性对项目都有效,比如 span 元素是可以使用 width 和 height 的,并且垂直方向上的 margin 和 padding 也有效。
还需要注意的是,项目是按照 flex 容器的 主轴依次排列 的,从 main start
到 main end
,默认情况下如果我们不给项目设置单独的 高度,那么该项目高度会占满整个 交叉轴范围,如果不设置单独的 宽度,那么项目的宽度由其内容规定。
important
关于项目在 flex 容器中的占位问题,具体需要结合容器的 flex-direction
、align-items
而定,即主轴方向和项目在交叉轴上的对齐方式,具体在 flex-direciton
和 align-items
会谈到。
<div class="container">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<span class="item">item</span>
<span class="item">item</span>
</div>
.container {
width: 500px;
height: 500px;
border: solid;
display: flex;
.item {
border: solid;
}
}
另外,flex 布局也解决了许多标准文档流中存在的一些问题,比如 margin 垂直方向的塌陷问题、margin: auto
只能进行水平居中的问题。
容器的属性(9 个)
属性 | 简述 |
---|---|
flex-direction | 规定容器主轴的方向 |
flex-wrap | 规定容器中的项目是否换行 |
flex-flow | flex-direciton 和 flex-wrap 的简写 |
justify-content | 规定项目在主轴上的对齐方式 |
align-items | 规定项目在交叉轴上的对齐方式 |
align-content | 规定多根轴线在交叉轴上的对齐方式 |
row-gap | 规定项目与项目之间的最小行间隔 |
column-gap | 规定项目与项目之间的最小列间隔 |
gap | row-gap 和 column-gap 的简写 |
flex-direction
该属性规定容器内主轴的方向,即项目的排列方向。
flex-direction: row | row-reverse | column | column-reverse;
row
(默认值):主轴水平从左往右,交叉轴从上往下row-reverse
:主轴水平从右往左,交叉轴从上往下column
:主轴垂直从上往下,交叉轴从左往右column-reverse
:主轴垂直从下往上,交叉轴从左往右
这里具体来讨论一下容器中项目的占位问题,前文中说到,默认情况下,不给项目设置高度,那么项目的高度会占满整个 交叉轴范围,不给项目设置宽度,那么项目的宽度由其内容而定。
这个实际上这与 主轴 的是水平还是垂直有关:
- 主轴水平,项目的水平占位就由内容规定,垂直占位则占满交叉轴
- 主轴垂直,项目的垂直占位就由内容规定,水平占位则占满交叉轴
flex-wrap
该属性规定容器内的项目是否换行,默认情况下,项目都排在一条线上,就算超出了容器范围也不会主动换行。
flex-wrap: nowrap | wrap | wrap-reverse;
nowrap
(默认值):不换行wrap
:换行,第一行在上方,新起的行在第一行下面从上往下排列wrap-reverse
:反向换行,新起的行从第一行上面从下往上排列(此时第一行会位于交叉轴的末端)
这里注意一下 nowrap
默认值,它会让项目全部依次排列在一条线上,并且当我们继续添加项目时如果会超出容器范围,那么此时会挤压所有项目的占位(平均挤压),就算项目设置了固定的占位大小(width or height),也会被挤压到不等于设置的占位大小,挤压的最大限度就是项目占位由其内容规定,此时如果继续添加项目,就会导致项目溢出容器范围。
我们来看下面这个例子:
.container {
width: 500px;
height: 500px;
border: solid;
display: flex;
.item {
width: 100px;
height: 100px;
border: solid;
}
}
这里可以看见,前面内容为 item 的项目已经的宽度已经由其内容(小于 100px)规定了,此时我们继续添加项目。
最终这个无内容的项目只剩下 border 占位,然后超出容器范围。
如果容器设置为 flex-wrap: wrap
,那么当一行的项目放不下时,就会自动换行。
需要注意的是,这时换行的项目并不会紧挨着上一行的项目另起一行进行排列(因为这里的项目指定了固定占位大小),这和 align-content
属性有关,现在只需要知道有这个行为即可。
如果换行过多,也会导致项目从交叉轴方向溢出。
flex-flow
该属性是 flex-direction
和 flex-wrap
的简写形式。
flex-flow: <flex-direction> | <flex-wrap>;
默认值为 flex-flow: row nowrap
。
justify-content
该属性规定了项目在主轴上的对齐方式。
justify-content: flex-start | flex-end | center | space-around | space-between |
space-evenly;
flex-start
(默认值):往主轴 起始端 对齐flex-end
:往主轴 结束端 对齐center
:在主轴居中space-around
:每个项目两侧有相同间距 x,那么两个项目直接的间距为 2x,项目与容器边缘的间距为 xspace-between
:项目在主轴两端对齐(项目与容器边缘间距为 0),两个项目之间的距离相同space-evenly
:项目与项目之间的间距,还有项目与容器边缘的间距都一样
align-items
该属性规定了项目在交叉轴上的对齐方式。
align-items: stretch | flex-start | flex-end | center | baseline;
stretch
(默认值):交叉轴垂直时,未指定项目的 height 或者 height 取值为 auto,则项目的高度占满整个容器,同理,交叉轴水平时,没有指定项目的 width,则项目的宽度占满整个容器flex-start
:项目在交叉轴的 起始端 对齐flex-end
:项目在交叉轴的 结束端 对齐center
:项目在交叉轴居中对齐baseline
:项目在交叉轴方向上以文字基线对齐,了解即可,这个并不常用
important
除了 align-items: stretch
,其余的取值对于项目在交叉轴的占位都是由内容决定(前提是没有指定 width or height)。
align-content
该属性规定了 多根轴线 在交叉轴上的对齐方式,前提必须设置 flex-wrap: wrap | wrap-reverse
,并且有多行项目,只有一行项目不会时,该属性不会生效。
这里解释一下,上面所说的 多根轴线 是什么意思,可以理解为 flex 容器中,项目换行以后,每一个项目所在排列在的一条直线上就可以看作一根轴线,这里的 多根轴线 就可以看作 多根平行的主轴,每根主轴都控制着该行项目的排列。
align-content: stretch | flex-start | flex-end | center | space-between |
space-around | space-evenly;
stretch
(默认值):在 css-tricks 中也有说normal
为默认值的,但是我自己测试了发现它们的行为都是一样的,它的作用是让轴线以align-items: stretch
且项目没有设置交叉轴方向的占位时项目的行为而定位的,可以理解为轴线平分填充了交叉轴,说得很难理解,具体看下面展示。flex-start
flex-end
center
space-between
space-around
当取值是默认的 stretch
时,多行项目是如下排列的:
里面的每一个项目都是有固定宽高的,且 align-items
为 stretch
,这里我们就来解释一下为什么新起行的项目之间会有一段空隙,这个行为实际上就是 align-content: stretch
的效果,现在我们把项目的高度设置为 auto,就会发现每一行项目拉伸,且平均占位了剩余的交叉轴空间:
所以,align-content: stretch
的效果就是让轴线拉伸平均分布在交叉轴剩余空间。
其他属性取值的效果可以参考下面,它们的原理和主轴上项目的对齐方式一样,这里不过是换成了每一行项目在交叉轴上的对齐方式:
important
关于 align-items
和 align-content
,对于初学者来说并不是很好分别,实际上只需要讨论 flex 容器 具有多行项目 情况下:
align-items
只会把所有项目看做一个整体去调整它在交叉轴上的对齐方式,每行项目之间的间距等并不会去理会align-content
是把每行的项目看作一个单位,它可以调整每行项目在交叉轴上的间距划分等对齐方式- 比如
align-content: center
会让每一行聚拢在交叉轴中部,此时每一行之间的间距为 0,但是align-items: center
只会将所有项目看做整体在交叉轴上居中,每一行之间的间距依旧保持
gap-row
与 gap-column
这两个属性的作用是用来设置 flex 容器中项目与项目之间的最小限度间隙,请注意它不会调整项目和容器边缘之间的间隙。
gap-row: <length>;
gap-column: <length>;
在某些情况这个属性比直接调整项目的 margin 更有效。
另外,这两个属性也有简写形式:
.container {
display: flex;
...
gap: 10px;
gap: 10px 20px; /* row-gap column gap */
row-gap: 10px;
column-gap: 20px;
}
important
它不仅适用于 flex 布局,也适用于网格和多列布局
项目的属性(6 个)
属性 | 简述 |
---|---|
order | 规定当前项目的排列顺序 |
flex-grow | 规定 flex 容器中剩余空间的多少应该分配给该项目 |
flex-shrink | 规定该项目的收缩规则 |
flex-basis | 规定该项目在主轴方向上的初始大小 |
flex | 是 flex-grow 、flex-shrink 和 flex-basis 的简写 |
align-self | 调整指定项目在交叉轴的对齐方式 |
order
该属性规定项目的排列顺序。数值越小,排列顺序离主轴和交叉轴的 起始端 越近,默认为 0,可以是负数。
order: <integer>;
这里需要注意一点的就是,当 flex 容器内有多行项目时,order 控制的项目的顺序是先沿主轴方向再沿交叉轴方向。
flex-grow
该属性可以规定项目占据 flex 容器主轴的剩余空间(优先级高于 width or height),不可为负数,默认值为 0,即项目不会自动增加占位。
flex-grow: <number>;
另外,flex-grow
也可以规定同一条主轴上的项目占位比例,比如一条主轴上有 4 个项目,它们的 flex-grow
的比值为 1:1:2:1
,那么第 3 个项目在主轴的占位是其余项目的两倍。
flex-shrink
该属性规定了项目的收缩程度,一般用于主轴上所有项目的原始宽度加起来比容器大时,并且 flex-wrap: nowrap
,此时就会挤压收缩主轴上的项目,默认值为 1,表示每一个项目都等比例收缩。
flex-shrink: <number>;
如果我们给主轴上的某个项目设置 flex-shrink: 0
,那么主轴上就算放再多的项目也能够保证该项目不发生挤压收缩。
flex-basis
该属性规定了项目在主轴方向上分配剩余空间之前元素的默认大小,优先级高于自身的 width or height,默认值为 auto。
flex-basis: 0 | 100% | auto | <length>;
它的主要作用就是保证主轴方向变化后,项目在主轴上的占位也由 flex-basis
决定,这样可以保证项目在主轴上的占位保持不变。
当取默认值 auto
时,如果我们没有给项目设置宽度,那么项目的宽度是由内容大小决定的。
如果是 flex-basis: 0 | 0%
,那么会以内容的一个单词、汉字的最大宽度作为项目宽度。
另外,对于百分比单位,计算值是相对于主轴的长度决定。
flex
该属性是 flex-grow
、flex-shrink
和 flex-basis
的简写,默认值为 flex: 0 1 auto
。
flex: none | [ <flex-grow> <flex-shrink>? || <flex-basis> ];
第一个参数是 flex-grow
,后面两个参数 flex-shrink
和 flex-basis
为可选参数。
建议使用该属性来控制项目的 flex-grow
、flex-shrink
和 flex-basis
,当我们给该属性一个值的时候:
.item {
flex: 1; /* 等价于 flex: 1 1 0% */
}
里面的 flex-shrink
默认为 1,flex-basis
会自动调整为 0%。
另外,该属性还可以直接取值为 auto
:
.item {
flex: auto; /* 等价于 flex: 1 1 auto */
}
align-self
该属性用于调整单个项目在交叉轴上的对齐方式,默认值为 auto,原理和 align-items
一致,区别就是前者用于调整单个项目在交叉轴上的对齐方式,后者则调整所有项目在交叉轴上的对齐方式。
align-self: auto | flex-start | flex-end | center | baseline | stretch;
取默认值 auto 的含义就是让项目在交叉轴上的对齐方式由 align-items
决定。