06.flex布局
06.flex布局
6.1 flex布局基础
flex布局是一种强大的布局,可以完成block和float不方便完成的布局
- 在父内容里面垂直居中一个块内容
- 使容器的所有子项占用等量的可用宽度/高度,而不管有多少宽度/高度可用
- 使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同
通过指定弹性盒子的分布方式、对齐方式和视觉顺序,可以轻易地完成对行列布局或是折断成多行
弹性容器:通过声明
display: flex或inline-flex,可以把容器变成弹性容器- 所有在其中的子元素都称为弹性元素
- 弹性容器的子元素的子元素不是弹性元素
- 绝对定位的子元素也是弹性元素,确定尺寸和位置时将此子元素当做容器中唯一的弹性元素
- 弹性容器
flex适合延以主轴实现特定布局,虽然实现双轴布局是可行的,但这不是弹性容器的最初目的
布局时将沿着两个轴来布局:

布局图 - 主轴(
main axis)是沿着flex元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为main start和main end - 交叉轴(
cross axis)是垂直于flex元素放置方向的轴。该轴的开始和结束被称为cross start和cross end
- 主轴(
弹性元素有以下特性
- 弹性元素的外边距不会折叠,
float和clear属性不起作用,不会因为float把弹性元素移出文档流 - 行内元素转用
display: flex后是块级的 - 绝对定位的弹性元素将移出文档流,不参与文档布局,但仍将受到弹性样式的影响
- 弹性元素的外边距不会折叠,
6.2 选定主轴
主轴方向:如果你想要的布局是从上到下、从左至右、从右至左的,抑或是从下到上的,可以使用
flex-direction属性控制排布弹性元素的主轴,下面是当文字方向direction为ltr,writing-mode为horizontal-tb时的显示效果row:默认值,子元素从左到右排成一排row-reverse:子元素从右到左排成一排column:子元素从上到下排成一列column-reverse:子元素从下到上排成一列
带reverse实际上是布局中的
main start和main end互换; 如果是文字方向为rtl,row和row-reverse显示效果将正好相反,即默认情况下是从右到左排成一排; 如果文字前进方向为vertical-lr,默认情况下是从上到下排成一排主轴换行
对于交叉轴(垂轴)而言,布局是通过主轴换行实现的,默认时,主轴是不会自动换行的,如果一行内容过多,子代会超过外边的弹性容器,可以使用
flex-wrap: wrap;换行- 默认值是不换行
nowrap,这可能导致容器溢出 flex元素被打断到多个行中wrap-reverse:和wrap的行为一样,但是cross-start和cross-end互换(相当于交叉轴反向显示)
flex-flow属性是flex-direction和flex-wrap的简写形式,由于定义弹性容器的换行方式和主轴方向,是可以只显式写其中一个值的
6.3 分配主轴空间
分配主轴空间的方式
justify-content属性定义浏览器如何沿着弹性容器的主轴分配内容元素之间和周围的空间,grid布局也使用这个属性,对应如何沿着网格容器的行向轴分配空间- 具体效果和取值如下,默认值是
normal相当于start,效果在代码中有注释 - 其中
flex-start和flex-end效果相当于start和end stretch一般是用于grid布局的,任何尺寸设置为auto的元素都会等比例地增加其尺寸(遵守max-width等的约束),以便完全填满容器,如果是flex布局,效果相当于start(flex的拉伸由flex属性控制)- 如果存在弹性元素即
flex-grow不为0,对齐不会生效,剩余空间会被弹性元素占满 - 可以在
start,center,end前面,添加safe和unsafe,默认相当于unsafesafe:如果元素溢出,会使用start对齐unsafe:哪怕元素溢出,也不修改对齐方式
具体效果示例<div id="container"> <div></div> <div></div> <div></div> </div> <select id="justifyContent"> <!-- 从行首开始排列。每行第一个元素与行首对齐,同时所有后续的元素与前一个对齐 --> <option value="start">start</option> <!-- 从行尾开始排列。每行最后一个元素与行尾对齐,同时所有前面的元素与后一个对齐 --> <option value="end">end</option> <!-- 相当于start --> <option value="flex-start">flex-start</option> <!-- 相当于end --> <option value="flex-end">flex-end</option> <!-- 伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同 --> <option value="center">center</option> <!-- 一个挨一个在对齐容器的边缘 --> <!-- 具体的排列和内联轴(文本方向的直线轴)有关 --> <!-- 效果分别和start, end相同 --> <!-- <option value="left">left</option> <option value="right">right</option> --> <!-- 在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首对齐,每行最后一个元素与行尾对齐 --> <option value="space-between" selected>space-between</option> <!-- 在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素到行首的距离和每行最后一个元素到行尾的距离将会是相邻元素之间距离的一半 --> <option value="space-around">space-around</option> <!-- flex 项都沿着主轴均匀分布在指定的对齐容器中。相邻 flex 项之间的间距,主轴起始位置到第一个 flex 项的间距,主轴结束位置到最后一个 flex 项的间距,都完全一样 --> <option value="space-evenly">space-evenly</option> <!-- 如果元素沿主轴的组合尺寸小于对齐容器的尺寸,任何尺寸设置为 auto 的元素都会等比例地增加其尺寸(而不是按比例增加) --> <option value="stretch">stretch</option> </select>#container { display: flex; justify-content: space-between; /* Can be changed in the live sample */ } #container > div { width: 100px; height: 100px; background: linear-gradient(-45deg, #788cff, #b4c8ff); border:#788cff 1px solid; }var justifyContent = document.getElementById("justifyContent"); justifyContent.addEventListener("change", function (evt) { document.getElementById("container").style.justifyContent = evt.target.value; });- 具体效果和取值如下,默认值是
6.4 交叉轴空间分配
align-content定义如何沿交叉轴分配空间,也用于定义grid布局如何分配主轴空间- 此属性在单行布局中无效,定义的是多主轴行如何分配空间,也就是
flex-wrap: no-wrap;时无效
具体效果示例<div id="container" class="flex"> <div id="item1">1</div> <div id="item2">2</div> <div id="item3">3</div> <div id="item4">4</div> <div id="item5">5</div> <div id="item6">6</div> </div> <div class="row"> <label for="display">display: </label> <select id="display"> <option value="flex">flex</option> <option value="grid">grid</option> </select> </div> <div class="row"> <label for="values">align-items: </label> <select id="values"> <option value="normal">normal</option> <option value="flex-start">flex-start</option> <option value="flex-end">flex-end</option> <option value="center" selected>center</option> <option value="baseline">baseline</option> <option value="stretch">stretch</option> <option value="start">start</option> <option value="end">end</option> <option value="self-start">self-start</option> <option value="self-end">self-end</option> <option value="first baseline">first baseline</option> <option value="last baseline">last baseline</option> </select> </div>#container { height: 200px; width: 240px; align-items: center; /* 可以在运行实例中更改 */ background-color: #8c8c8c; } .flex { display: flex; flex-wrap: wrap; } .grid { display: grid; grid-template-columns: repeat(auto-fill, 50px); } #container > div { box-sizing: border-box; border: 2px solid #8c8c8c; width: 50px; display: flex; align-items: center; justify-content: center; } #item1 { background-color: #8cffa0; min-height: 30px; } #item2 { background-color: #a0c8ff; min-height: 50px; } #item3 { background-color: #ffa08c; min-height: 40px; } #item4 { background-color: #ffff8c; min-height: 60px; } #item5 { background-color: #ff8cff; min-height: 70px; } #item6 { background-color: #8cffff; min-height: 50px; font-size: 30px; } select { font-size: 16px; } .row { margin-top: 10px; }const values = document.getElementById("values"); const display = document.getElementById("display"); const container = document.getElementById("container"); values.addEventListener("change", (evt) => { container.style.alignItems = evt.target.value; }); display.addEventListener("change", (evt) => { container.className = evt.target.value; });- 此属性在单行布局中无效,定义的是多主轴行如何分配空间,也就是
6.5 主轴元素对齐
align-items属性定义的是容器内的弹性元素在主轴方向上如何对齐,实际上相当于同时设置每个子弹性元素的align-self,这个值可以被子元素的align-self覆盖,grid布局也使用这个属性控制元素在块向轴的对齐方式- 具体效果和取值如下,大部分取值和
justify-content相同 baseline是基于元素的flex基线对齐,子元素上效果相当于center,但从弹性容器的角度上相当于是start(如果子元素设置了上外边距,会离上面有一定距离,同时baseline效果受字号行高等属性的影响)- 默认值是
normal,对于flex和grid布局来说,效果都相当于stretch stretch会使元素扩大填满交叉轴容器空间,会受到元素的width和height属性限制- 和
justify-content一样,有safe和unsafe两种前置关键字
align-self的取值和效果也是这样的,可用于修改单个子元素的对齐效果,应该在对应子元素上使用具体效果示例<div id="container" class="flex"> <div id="item1">1</div> <div id="item2">2</div> <div id="item3">3</div> <div id="item4">4</div> <div id="item5">5</div> <div id="item6">6</div> </div> <div class="row"> <label for="display">display: </label> <select id="display"> <option value="flex">flex</option> <option value="grid">grid</option> </select> </div> <div class="row"> <label for="values">align-items: </label> <select id="values"> <option value="normal">normal</option> <option value="flex-start">flex-start</option> <option value="flex-end">flex-end</option> <option value="center" selected>center</option> <option value="baseline">baseline</option> <option value="stretch">stretch</option> <option value="start">start</option> <option value="end">end</option> <option value="self-start">self-start</option> <option value="self-end">self-end</option> <option value="first baseline">first baseline</option> <option value="last baseline">last baseline</option> </select> </div>#container { height: 200px; width: 240px; align-items: center; background-color: #8c8c8c; } .flex { display: flex; flex-wrap: wrap; } .grid { display: grid; grid-template-columns: repeat(auto-fill, 50px); } #container > div { box-sizing: border-box; border: 2px solid #8c8c8c; width: 50px; display: flex; align-items: center; justify-content: center; } #item1 { background-color: #8cffa0; min-height: 30px; } #item2 { background-color: #a0c8ff; min-height: 50px; } #item3 { background-color: #ffa08c; min-height: 40px; } #item4 { background-color: #ffff8c; min-height: 60px; } #item5 { background-color: #ff8cff; min-height: 70px; } #item6 { background-color: #8cffff; min-height: 50px; font-size: 30px; } select { font-size: 16px; } .row { margin-top: 10px; }const values = document.getElementById("values"); const display = document.getElementById("display"); const container = document.getElementById("container"); values.addEventListener("change", (evt) => { container.style.alignItems = evt.target.value; }); display.addEventListener("change", (evt) => { container.className = evt.target.value; });- 具体效果和取值如下,大部分取值和
也有
justify-items,但在弹性布局中此值将被忽略
6.6 作用于弹性元素自身的属性
flex是一个作用在弹性元素自身的属性的总和,此属性是以下 CSS 属性的简写:flex-grow:设置flex项主尺寸的flex增长系数,所有的子元素将按比例分配主轴剩余空间,剩余空间是flex容器的大小减去所有flex项的大小加起来的大小,初始值是0flex-shrink:属性指定了flex元素的主尺寸收缩规则。flex元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据flex-shrink的值,初始值是1flex-basis:指定了flex元素在主轴方向上的初始大小(伸缩基准值),如果一个元素有flex-basis和主轴对应方向的长度width或height,以flex-basis为准,初始值为auto- 百分数时按父容器主轴尺寸百分比计算
content:使用元素内容尺寸,相当于max-content,忽略width/height属性auto:使用元素主轴尺寸,如果没显式设置宽高,对应内容尺寸0% vs 0:0%是相对大小,0是绝对长度,虽然两个都被解析为初始大小0px,但0%会在父容器没有设置主轴尺寸时作为content,这会影响自身如果是需要滚动的元素(设置了最小高度min-height和滚动条显示overflow),导致撑开父容器的空间,而不是自身出现滚动条- 此属性优先级在
width/height属性之前,但优先级低于max-width和min-content等约束属性
0% 和 0 区别<div class="container"> <div class="box" style="flex:0; flex-basis: 0px;"> <div class="content"> flex-basis: 0px; </div> </div> </div> <div class="container"> <div class="box" style="flex:0"> <div class="content"> flex-basis: 0%; </div> </div> </div>.container { display: inline-flex; vertical-align: top; flex-direction: column; padding: 5px; width: 100px; border: 1px solid red; overflow: auto; } .box { min-height: 70px; } .content { height: 150px; background: lightsalmon; }
flex语法- 单值:必须是一个无单位数字或有单位数字(也可以是关键字
content),分别对应flex-grow和flex-basis,其余值相当于使用flex: 1 1 0%设置flex: 1:相当于flex: 1 1 0%,设置元素可伸缩,同时主轴空间初始宽度为0%,空间根据flex-grow值进行分配flex: auto:相当于flex: 1 1 auto,设置元素可伸缩,主轴空间初始值为auto,即元素内容尺寸flex: 0:相当于flex: 0 1 0%,设置元素不可伸缩,同时主轴空间初始宽度为0%,如果没有内容就不显示,如果有内容根据最小内容尺寸显示
- 双值:第一个值是
flex-grow,第二个值是一个无单位数字或有单位数字,分别对应flex-shrink和flex-basis - 三值:依次为
flex-grow、flex-shrink、flex-basis initial元素会根据自身宽高设置尺寸。它会缩短自身以适应flex容器,但不会伸长并吸收flex容器中的额外自由空间来适应flex容器。相当于将属性设置为flex: 0 1 auto;auto元素会根据自身的宽度与高度来确定尺寸,但是会伸长并吸收flex容器中额外的自由空间,也会缩短自身来适应flex容器。这相当于将属性设置为flex: 1 1 auto;none元素会根据自身宽高来设置尺寸。它是完全非弹性的:既不会缩短,也不会伸长来适应flex容器。相当于将属性设置为flex: 0 0 auto;
对于图片和视频使用
flex属性自动占满剩余空间,似乎需要为图片额外添加overflow: hidden;才能生效- 单值:必须是一个无单位数字或有单位数字(也可以是关键字
