flex 布局很重要很核心的一个概念就是 , flex 是有两个轴, 一个主轴, 一个交叉轴. 主轴永远和交叉轴互相垂直;
在未对子元素设置任何样式时, 子元素在主轴的表现, 由子元素内容决定, 而在交叉轴上则是占满交叉轴, 即为交叉轴的 100%;
在 flex 遇到 margin 和定义宽度, 总是会遇到一些意料之外的表现. 所以尽量少的 flex 属性和其他可以改变元素宽度和高度的样式混用.
基本 html 骨架如下:
<div class="container">
<div class="item"></item>
</div>
container 属性
1. 定义 flex 容器
在 container
定义 flex
布局表现.
- display : flex ;
container
独自占一整行, 宽度为 100%;
- display: inline-flex;
container
的宽度由子元素 item
的宽度决定. 能和行列元素 , dispaly:inline-block 的元素 , display:inline-flex 的元素并排显示在一行
2. 定义 item 的排列方向, 也就是定义主轴方向
子元素, 总是按照主轴方向进行排布.
flex-direction : row ; // 主轴方向为横向从左到右 →
flex-direction: row-reverse; // 主轴方向为横向从右到左 ←
flex-direction: column; // 主轴方向为竖向, 从上到下 ↓
flex-direction: column-reverse; // 主轴方向为竖向, 从下到上 ↑
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: orange;
margin-bottom: 20px;
display: flex;
height: 100px;
}
.container-row {
flex-direction: row;
}
.container-row-reverse {
flex-direction: row-reverse;
}
.container-column {
flex-direction: column;
}
.container-column-reverse {
flex-direction: column-reverse;
}
.item {
background: pink;
}
</style>
<h3>flex-direction: row</h3>
<div class="container container-row">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<h3>flex-direction: row-reverse</h3>
<div class="container container-row-reverse">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<h3>flex-direction: container-column</h3>
<div class="container container-column">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<h3>flex-direction: container-column-reverse</h3>
<div class="container container-column-reverse">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
- 子元素
item
交叉轴的尺寸默认为容易的 100%;- 不管排布方向 , 容器
container
设置display:flex
时的默认宽度为 100% ;- 不管排布方向, 容器
container
设置display:inline-flex
时的默认宽度和高度都为子元素自适应 ;
定义对齐方式
主轴对齐 : justify-cotent
- justify-content:flex-start; // 开始对齐 ( 默认 )
- justify-content:flex-end; // 结尾对齐
- justify-content:center; // 中间对齐
- justify-content:space-between; // 两端对齐,子元素间空隙相等,空隙的个数为n-1
- justify-content:space-around; // 两端也留空隙,空隙的个数为n-1+2,但两端的空隙和子元素间的空隙并不相等,两端是其他的1/2
- justify-content: space-evenly; // n-1+2个空隙,各空隙均等
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
margin-bottom: 20px;
display: inline-flex;
width: 160px;
height: 100px;
margin-right: 10px;
}
.container-start {
justify-content: flex-start;
}
.container-end {
justify-content: flex-end;
}
.container-center {
justify-content: center;
}
.container-between {
justify-content: space-between;
}
.container-around {
justify-content: space-around;
}
.container-evenly {
justify-content:space-evenly ;
}
.item {
background: orange;
}
</style>
<h3>justify-content:</h3>
<div class="container container-start">
<div class="item">-</div>
<div class="item">start</div>
<div class="item">-</div>
</div>
<div class="container container-end">
<div class="item">-</div>
<div class="item">end</div>
<div class="item">-</div>
</div>
<div class="container container-center">
<div class="item">-</div>
<div class="item">center</div>
<div class="item">-</div>
</div>
<div class="container container-between">
<div class="item">-</div>
<div class="item">between</div>
<div class="item">-</div>
</div>
<div class="container container-around">
<div class="item">-</div>
<div class="item">around</div>
<div class="item">-</div>
</div>
<div class="container container-evenly">
<div class="item">-</div>
<div class="item">evenly</div>
<div class="item">-</div>
</div>
效果图如下:
- justify-content:flex-start; // 开始对齐 ( 默认 )
- justify-content:flex-end; // 结尾对齐
- justify-content:center; // 中间对齐
- justify-content:space-between; // 两端对齐,子元素间空隙相等,空隙的个数为n-1
- justify-content:space-around; // 两端也留空隙,空隙的个数为n-1+2,但两端的空隙和子元素间的空隙并不相等,两端是其他的1/2
- justify-content: space-evenly; // n-1+2个空隙,各空隙均等
交叉轴单行对齐: align-items
- align-items:flex-start; // 开始对齐
- align-items:flex-end; // 结尾对齐
- align-items:center; // 居中对齐
- align-items:stretch; // 拉升到容器交叉轴大小 ( 默认 )
- align-items:baseline; // 基线对齐
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
margin-bottom: 20px;
display: inline-flex;
width: 160px;
height: 100px;
margin-right: 10px;
}
.container-start {
align-items: flex-start;
}
.container-end {
align-items: flex-end;
}
.container-center {
align-items: center;
}
.container-stretch {
align-items: stretch;
}
.container-baseline {
align-items: baseline;
}
.item {
background: orange;
}
</style>
<h3>align-items:</h3>
<div class="container">
<div class="item">-</div>
<div class="item">default</div>
<div class="item">-</div>
</div>
<div class="container container-start">
<div class="item">-</div>
<div class="item">start</div>
<div class="item">-</div>
</div>
<div class="container container-end">
<div class="item">-</div>
<div class="item">end</div>
<div class="item">-</div>
</div>
<div class="container container-center">
<div class="item">-</div>
<div class="item">center</div>
<div class="item">-</div>
</div>
<div class="container container-stretch">
<div class="item">-</div>
<div class="item">stretch</div>
<div class="item">-</div>
</div>
<div class="container container-baseline">
<div class="item">-</div>
<div class="item">baseline</div>
<div class="item">-</div>
</div>
效果如下:
- align-items:flex-start; // 开始对齐
- align-items:flex-end; // 结尾对齐
- align-items:center; // 居中对齐
- align-items:stretch; // 拉升到容器交叉轴大小 ( 默认 )
- align-items:baseline; // 基线对齐
当多个
inline-flex
同处一行, 而align-item
不一致时, 就如上图所示.
交叉轴多行对齐: align-content
- align-content:flex-start; //
- align-content:flex-end;
- align-content:center;
- align-content:stretch;
- align-content:space-between;
- align-content:space-around;
- align-content:space-evenly;
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
margin-bottom: 20px;
display: inline-flex;
width: 160px;
height: 100px;
margin-right: 10px;
flex-wrap: wrap;
}
.container-start {
align-content: flex-start;
}
.container-end {
align-content: flex-end;
}
.container-center {
align-content: center;
}
.container-stretch {
align-content: stretch;
}
.container-between{
align-content: space-between;
}
.container-around {
align-content: space-around;
}
.container-evenly {
align-content: space-evenly;
}
.item {
background: orange;
width:80px;
}
</style>
<h3>align-content:</h3>
<div class="container">
<div class="item">-</div>
<div class="item">default</div>
<div class="item">-</div>
</div>
<div class="container container-start">
<div class="item">-</div>
<div class="item">start</div>
<div class="item">-</div>
</div>
<div class="container container-end">
<div class="item">-</div>
<div class="item">end</div>
<div class="item">-</div>
</div>
<div class="container container-center">
<div class="item">-</div>
<div class="item">center</div>
<div class="item">-</div>
</div>
<div class="container container-stretch">
<div class="item">-</div>
<div class="item">stretch</div>
<div class="item">-</div>
</div>
<div class="container container-between">
<div class="item">-</div>
<div class="item">between</div>
<div class="item">-</div>
</div>
<div class="container container-around">
<div class="item">-</div>
<div class="item">around</div>
<div class="item">-</div>
</div>
<div class="container container-evenly">
<div class="item">-</div>
<div class="item">evenly</div>
<div class="item">-</div>
</div>
效果如下:
基本类似
justify-content
的表现. 只是是相对多行内容来说 , 以交叉轴为对齐方向.
这里, 注意需container
设置flex-wrap:wrap
样式强制子元素换行.
定义主轴方向是否换行
- flex-wrap:nowrap; // (默认),不换行
- flex-wrap:wrap; // 强制换行
- flex-wrap:wrap-reverse; // 强制反向换行
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
margin-bottom: 20px;
display: inline-flex;
width: 160px;
height: 140px;
margin-right: 10px;
}
.container-nowrap {
flex-wrap: nowrap;
}
.container-wrap{
flex-wrap: wrap;
}
.container-wrap-reverse{
flex-wrap: wrap-reverse;
}
.item {
background: orange;
width:60px;
height: 40px;
border:1px solid red;
}
</style>
<h3>flex-wrap:</h3>
<div class="container">
<div class="item">1</div>
<div class="item">default</div>
<div class="item">2</div>
</div>
<div class="container container-nowrap">
<div class="item">1</div>
<div class="item">nowrap</div>
<div class="item">2</div>
</div>
<div class="container container-wrap">
<div class="item">1</div>
<div class="item">wrap</div>
<div class="item">2</div>
</div>
<div class="container container-wrap-reverse">
<div class="item">1</div>
<div class="item">wrap-reverse</div>
<div class="item">2</div>
</div>
效果如下:
主轴方向和换行的合并简写:
flex-flow: row nowrap;
( 默认表现: 横向不换行 )
items 属性
1. order 自定义主轴上排列位置 , 可正数可负数, 默认值为0 ;
在同一个 flex container
容器下, 所有直接子元素会按设置的 order
的大小排序来显示. 负数 > 0 ( 默认 ) > 正数
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
display: flex;
height: 140px;
}
.item {
background: orange;
width: 60px;
border-right: 1px solid red;
}
.order-less-zero{
order: -1;
}
.order-three {
order: 3;
}
.order-one {
order: 1;
}
.order-zero {
order: 0;
}
</style>
<h3>order:</h3>
<div class="container">
<div class="item order-three">3</div>
<div class="item order-one">1</div>
<div class="item order-zero">0</div>
<div class="item order-less-zero">-1</div>
<div class="item order-default">default</div>
</div>
效果如下:
2. flex-grow , 子元素主轴上所占比例, 默认值为 0;
- 当
item
只有一个设置特殊值, 比如默认的都是 0 , 给其中某一个设置特殊值 ( 非负数 ) 时, 特殊的item
占满剩余空间. - 当设置所有
item
的flex-grow
为 1 , 一个特殊的为2
的话, 则该特殊元素, 是比其他设置为 1 的要宽一些, 但却并不是严格的设置的 flex-grow 的倍数的关系. - 多个不同的 flex-grow ? 没多大意义. 因为简单的两倍关系都没办法保证.
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
display: flex;
height: 140px;
margin-bottom: 10px;
}
.item {
background: orange;
border-right: 1px solid red;
padding:0 10px;
}
.one-grow .item-special {
flex-grow: 1;
}
.two-grow .item{
flex-grow: 1;
}
.two-grow .grow-2{
flex-grow: 4;
}
.many-grow .grow-1{
flex-grow: 1;
}
.many-grow .grow-2{
flex-grow: 2;
}
.many-grow .grow-3{
flex-grow: 3;
}
.many-grow .grow-4{
flex-grow: 4;
}
</style>
<h3>one grow:</h3>
<div class="container one-grow">
<div class="item">3</div>
<div class="item">发发呆发发呆发</div>
<div class="item">内容不定宽</div>
<div class="item item-special">特殊值的 grow flex-grow:1</div>
</div>
<h3>two grow:</h3>
<div class="container two-grow">
<div class="item">3</div>
<div class="item">发发呆发发呆发</div>
<div class="item">内容不定宽</div>
<div class="item grow-2">2</div>
<div class="item grow-2">内容不定宽123大师傅</div>
</div>
可以看出, two-grow 中设置不同的 flex-grow , 效果真的预料不到.
flex-grow:2 ; 的 并不一定是 flex-grow:1 的两倍, 设置可能还小于.
鸡肋.
在其他子元素, 默认为0 , 设置一个元素为 大于0 的值, 可以实现:
1. 单个元素可以占满容器的主轴
2. 在有其他的元素时, 可以占满剩下的所有空间.
flex-shrink ; 当父容器不足以排列所有的子元素, 各个元素压缩的比例,
- 默认为 1 , 也就是各个元素都压缩相同的空间
- 全部默认为 1 , 一个特殊的为 2 时, 为 2 的压缩比例就大一点.
- 超出父容器部分将由每个子元素消化,即单个子元素每个减少宽度以不超出容器.比如5个元素,容器超出200px, 那么每个元素则需在原来的基础上减少40px;而假如5个元素的flex:shrink分别为1:1:1:1:6, 那么结果则是最后一个减少120px
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
display: flex;
height: 140px;
margin-bottom: 10px;
}
.item {
background: orange;
border-right: 1px solid red;
box-sizing: border-box;
width: 200px;
}
.shrink-6 {
flex-shrink: 6;
}
</style>
<h3>shrink:</h3>
<div class="container">
<div class="item">1</div>
<div class="item">1</div>
<div class="item">1</div>
<div class="item">1</div>
<div class="item shrink-6">6</div>
</div>
flex-basis ; 可以用来定义各个元素之间的比例.
在压缩的时候, 始终保持 basis 的比例.
比如 5 个子元素 , 4个设置为 10% , 1个设置为 60%;
那么容器宽度为 1000 时, 就是 4个元素为 100 , 另一个为 600
如果容器宽度为 200 时, 就是 4个元素为 20 . 另一个为 120;
又比如5个元素, 1个设置 flex-basis 为 100px , 3个设置为10%, 1个设置为 60% ;
那么容器宽度为500px 时, 先算出各元素的应该有的宽度 , 100:50:50:50:300 也就是 2:1:1:1:6 ; 那么 flex-basis 设置为100的宽度应该就是差不多 500* 2/11 = 95px
flex-basis 和 flex-shrink 类似, 就是先要得出每一个元素所占的比例,
flex-basis 为正向比例, 占多少比例乘以现在容器的宽度就是元素的宽度;
而 flex-shrink 则是反向, 先算出要缩减的比例, 然后按比例在每一个元素上面销掉.
align-self , 重定义交叉轴的对齐方式
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
display: flex;
height: 140px;
margin-bottom: 10px;
align-items: center;
}
.item {
background: orange;
border-right: 1px solid red;
box-sizing: border-box;
flex-basis: 20%;
}
.align-self {
align-self: flex-start;
}
</style>
<div class="container">
<div class="item">法法阿凡达</div>
<div class="item">1</div>
<div class="item">1</div>
<div class="item">1</div>
<div class="item align-self">6</div>
</div>
flex 应用场景
- 子元素不定宽高居中
flex + justify-content: center + align-items: center;
<style>
* {
margin: 0;
padding: 0;
}
.container {
background: pink;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
.inner{
height: 80px;
width:80px;
background:orange;
}
</style>
<div class="container">
<div class="inner">
</div>
</div>
- 分列布局
.container{
display:flex;
}
.left{
order:-1;
flex-basis:100px;
}
.main{
flex-grow:1;
}
.right{
flex-basis:100px;
}
<div class="container">
<div class="main">main</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
- 类似购物车
toolbar
<style>
* {
margin: 0;
padding: 0;
}
body {
color: #f5f5f5;
}
.tool-bar {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
background: #fff;
display: flex;
}
button {
appearance: none;
-webkit-appearance: none;
background: transparent;
border: none;
color: #333;
padding: 0;
margin: 0;
}
.tool-bar-sm {
display: flex;
}
.tool-bar-sm button {
width: 50px;
box-sizing: border-box;
border-right: 1px solid #e1e1e1;
border-top: 1px solid #e1e1e1;
}
.tool-bar-lg {
flex-grow: 1;
display: flex;
}
.tool-bar-lg button {
flex-basis: 100%;
text-align: center;
color:#fff;
}
.add-shopcar{
background: #ff9600;
}
.buy-now{
background: #e4393c;
}
</style>
<div class="tool-bar">
<div class="tool-bar-sm">
<button>评论</button>
<button>点赞</button>
<button>收藏</button>
</div>
<div class="tool-bar-lg">
<button class="add-shopcar">加入购物车</button>
<button class="buy-now">立即购买</button>
</div>
</div>
效果如下:
拆分小按钮组 和 大按钮组,
小按钮组每个按钮固定宽度
大按钮组占据所有非小按钮组的空间. 每个按钮设置flex-basis
为100% , 保证每个大按钮占据同样的宽度 , 即宽度/个数
的 宽度.
效果: 小按钮始终保持定义的宽度, 而大按钮则根据屏幕宽度自适应. 添加删除按钮, 都不影响布局效果.
- 多列布局
justify-content:space-between; 虽然可以实现多个元素之间保持相等的间距. 但是在三列中, 碰到最后剩余两个数据的时候, 就会出现, 两个元素靠两边对齐, 中间空缺. 所以此处只借用 flex 布局弥补 float 布局的, 左边元素高出哪怕一个像素, 也会阻挡, 元素不能往左浮的尴尬.
<style>
* {
margin: 0;
padding: 0;
}
ul {
margin-left: -18px;
margin-right: 0;
display: flex;
flex-wrap: wrap;
/* justify-content: space-between; */
}
li {
list-style: none;
width: 25%;
height: 80px;
margin-bottom: 10px;
background: pink;
}
.tall{
height: 86px;
}
.inner {
margin-left: 18px;
background: orange;
}
</style>
<ul>
<li>
<div class="inner">1</div>
</li>
<li class="tall">
<div class="inner">2</div>
</li>
<li>
<div class="inner">3</div>
</li>
<li>
<div class="inner">4</div>
</li>
<li>
<div class="inner">5</div>
</li>
<li>
<div class="inner">5</div>
</li>
</ul>
效果如下:
也就是说, 第2块, 就算高度是超出了其他, 第5块也是能排在最左边. 而用浮动, 那第5块会被挡在第2块右边.