Flex布局-容器项
弹性盒子是一种用于 按行 或 按列的一维布局方法
.
元素可以膨胀
以填充额外的空间, 也可以 收缩
以适应更小的空间.
flex 重点概览
对于 flex 重要的理解点在于:
- 主轴与交叉轴
- 换行与缩写
- 主轴对齐方式
- 交叉轴对齐方式
基于了解完上面的内容, 我们能用 flex 布局实现如下几种最常见的布局:
- 内联和块的 上下左右居中布局
- 不定项居中布局
- 均分列布局
- 组合嵌套布局
接着是关于 flex-子项
的重点:
- flex-grow: 扩展比例
- flex-shrink 收缩比例
- flex-basis 及flex缩写
- order 与 align-self
最后同样是基于子项的属性, 完成一些常用的子项布局:
- 等高布局
- 两列与三列布局
- 粘性页脚布局
- 溢出项布局
可以发现这个 flex 是真的很强, 相对于上面的内容如果用定位 + 浮动的方式, 搞起来还是超级麻烦的哦
主轴与交叉轴
要形成 flex 布局, 首先需要一个父容器 flex-container, 然后是里面的子项 flex-item.
主轴
主轴 main-axis 默认是水平轴, 交叉轴 cross-axis 则垂直于主轴, 因此子元素默认是水平排列的. 要注意的是主轴和交叉轴, 包括起点, 终点都是可以互换的, 非常灵活.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
/* 这里用的是 display 的内部值属性 */
display: flex;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</body>
</html>
特别要注意区分 flex容器 和 flex子项的属性, 千万别写混了.
flex 容器属性 | flex 子项属性 |
---|---|
flex-direction | order |
flex-wrap | flex-grow |
flex-flow | flex-shrink |
justify-content | flex-basis |
align-items | flex |
align-content | align-self |
交叉轴
flex-direction 其实就是设置主轴是行还是列, 且起始位置是否要逆反而已啦. 要列它一共有 4个属性值:
- row (默认)
- row-reverse
- column
- column-reverse
默认是水平布局, 当 flex-direction: row-reverse 时候, 子项从右往左排列.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
/* 这里用的是 display 的内部值属性 */
display: flex;
/* 改变主轴起点位置, 水平时, 左->右; reverse: 从右->左 */
flex-direction: row-reverse;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</body>
</html>
当我们改变为垂直布局时, flex-direction: column / column-reverse 子项从上到下 或 从下往上排列.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
/* 改变主轴起点位置, 垂直时, 默认上->下; reverse: 下 -> 上 */
/* flex-direction: column; */
flex-direction: column-reverse;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</body>
</html>
换行与缩写
flex-wrap 用来设置当子项宽度超出容器时, 是否换行的问题, 主要有 3 个值:
- nowrap (默认) , 默认不换行, 进行一行的压缩, 宽度不会溢出父容器, 内容往里压缩啦. 但超级多也会溢出.
- wrap
- wrap-reverse
当弹性的子元素没有 width 时, 宽度会根据内容撑开; 当不设置 height 时, 会自动撑满容器
当主轴是 row 时:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
/* 元素尺寸超出, 可设置换行, 但是按父容器百分比平分, 2行的话就是 50% 的位置 */
/* 但如果父容器没有高度的话, 那就顺势挨在一起了. */
/* flex-wrap: wrap; */
/* reverse 也可设置从底部开始折行, 但这种用得比较少 */
flex-wrap: wrap-reverse;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
</div>
</body>
</html>
当主轴是 column 时:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
/* 元素尺寸超出, 可设置换列, 但是按父容器百分比平分, 2列的话就是 50% 的位置 */
/* 但如果父容器没有宽的话, 那就顺势挨在一起了. */
flex-direction: column;
/* flex-wrap: wrap; */
/* reverse 也可设置从底部开始折行, 但这种用得比较少 */
flex-wrap: wrap-reverse;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
</div>
</body>
</html>
但需注意的是, flex 布局更倾向于一维的布局, 如果是设计行和列的那还是得 grid 比较适合.
通常我用flex最多的就是, 一维横向, 子元素水平垂直居中就可以啦.
flex-flow
这个属性其实就是 flex-direction 和 flex-wrap 的缩写而已啦.
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
/* flex-direction: column;
flex-wrap: wrap; */
/* 上面两行可简写为一行 */
/* flex-flow: column wrap; */
flex-flow: wrap;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
为了降低记忆难度, 我感觉缩写啥, 就直接全写得了, 也不是那么费事.
主轴对齐
justify-content 主轴对齐, 即设置主轴元素的对齐方式, 主要有如下:
- flex-start (默认)
- flex-end
- center
- space-around
- space-between
- space-evenly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
/* 子元素默认对齐方式是 flex-start 紧挨着 */
/* justify-content: flex-start; */
/* 右对齐方式 */
/* justify-content: flex-end; */
/* 居中对齐 */
/* justify-content: center; */
/* 分散对齐, 最左/最右 的空间是一致的, 若不设置父容器宽, 则默认均分浏览器视口 */
/* justify-content: space-around; */
/* 两端对齐, 两侧分别顶到两个断点, 再来进行平分剩余空间 */
/* justify-content: space-between; */
/* 平均分配, 子项之间的距离是相等的 */
justify-content: space-evenly;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
</body>
</html>
当主轴为 cloumn 时, 也是一样的, 相当于转换一下而已.
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
flex-direction: column;
/* 子元素默认对齐方式是 flex-start 列 */
justify-content: flex-start;
/* 下对齐方式 */
/* justify-content: flex-end; */
/* 居中对齐 */
/* justify-content: center; */
/* 分散对齐, 最上/最下 的空间是一致的, 不设高时候, 按内容撑开 */
/* justify-content: space-around; */
/* 两端对齐, 两侧分别顶到两个断点, 再来进行平分剩余空间 */
/* justify-content: space-between; */
/* 平均分配, 子项之间的距离是相等的 */
/* justify-content: space-evenly; */
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
交叉轴对齐
交叉轴的对齐方式比主轴要更强大一些, 因为它有两个兄弟呀.
align-content
这个 align-content 和 justify-content 还是很像的, 唯一的特点是它必须要有换行才能生效.
- strech (默认)
- flex-start
- flex-end
- center
- space-around
- space-between
- space-evenly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>align-content</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
flex-wrap: wrap;
/* 当不换行的时候, align-content 不生效 */
/* align-content: flex-end; */
/* align-content: stretch; */
/* align-content: space-around; */
/* align-content: space-between; */
align-content: space-evenly;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
</div>
</body>
</html>
align-items
它是针对容器中, 针对每一行的对齐方式
, 而 align-content 是针对整体. 在实际应用中, 针对每一行的方式则用的更多些. 毕竟用 flex 是用来解决一维布局的, 换行就搞起来有点麻烦, 不如用 grid 操作.
- stretch (默认)
- flex-start
- flex-end
- center
- baseline -- 用得少
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>align-items</title>
<style>
.main {
width: 500px;
height: 500px;
background-color: pink;
display: flex;
flex-wrap: wrap;
/* align-items: 每一行的对齐 */
/* align-items: flex-start; */
align-items: center;
}
.main div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
</div>
</body>
</html>
从我的应用实践中, 就水平垂直居中用的比较多一些, 其他的换行都不咋用的.
. flex-container {
dispaly: flex;
justify-content: center;
align-items: center;
}
水平垂直居中布局
即容器内元素的水平和居中对齐, 根据内容.
内联元素: 文本垂直水平居中
- 水平居中: justify-content: center;
- 垂直居中: align-items: center
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文字水平垂直居中</title>
<style>
.box {
width: 300px;
height: 200px;
background-color: pink;
/* 水平垂直居中 */
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div class="box">哈哈哈哈哈</div>
</body>
</html>
这样就轻松搞定了. 但如果我们不用 flex 的话, 如果只是垂直居中, 就可以用 行高 = 盒子高
.
<style>
.box {
width: 300px;
height: 200px;
background-color: pink;
/* f水平垂直居中 */
text-align: center;
line-height: 200px;
}
</style>
但这种一旦涉及多行文字, 这种设置行高的方式就会对每行文字撑大一个空间, 就乱了. 但 flex 没有问题.
块级元素: 垂直水平居中
- 水平居中: justify-content: center;
- 垂直居中: align-items: center
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>块元素-水平垂直居中</title>
<style>
.box {
width: 300px;
height: 200px;
background-color: pink;
/* 块元素 水平垂直居中 */
display: flex;
justify-content: center;
align-items: center;
}
.box div {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box">
<div>item</div>
</div>
</body>
</html>
如果不用 flex 的话, 我们可以通过定位来实现哈, 即 子绝父相
.
<style>
.box {
width: 300px;
height: 200px;
background-color: pink;
/* 块元素 水平垂直居中, 子绝父相 */
position: relative;
}
.box div {
width: 100px;
height: 100px;
background-color: skyblue;
/* 子: 绝对定位, 参考父元素(设置了 relative) */
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
或者也可用 margin: auto
来做, 设置绝对定位, 然后 top / right / bottom / left 都设置为 0 即可.
<style>
.box {
width: 300px;
height: 200px;
background-color: pink;
position: relative;
}
.box div {
width: 100px;
height: 100px;
background-color: skyblue;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
</style>
对比发现, 还是这个 flex 布局比较好用呀.
不定项居中对齐
就中间元素多少不清楚, 但需要进行居中对齐, 最常用的比如轮播图里面, 下面的切换小点点,
还有就是像页面分页器在底部的居中对齐等.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>不定项居中对齐</title>
<style>
.box {
width: 300px;
height: 150px;
background-color: pink;
display: flex;
justify-content: center;
align-items: flex-end;
}
.box div {
width: 30px;
height: 30px;
background-color: skyblue;
border-radius: 50%;
margin: 10px;
}
</style>
</head>
<body>
<div class="box">
<div></div>
<div></div>
<div></div>
<!-- 多项也能进行居中 -->
<div></div>
<div></div>
</div>
</body>
</html>
同样如果不用 flex , 则我们可以利用 position
来做:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>定位实现: 不定项居中对齐</title>
<style>
.box {
width: 300px;
height: 150px;
background-color: pink;
/* 子绝父相 */
position: relative;
}
.box section {
/* text-align 对内联样式起作用, 块则无效 */
text-align: center;
width: 100%;
position: absolute;
bottom: 0;
font-size: 0;
}
.box div {
width: 30px;
height: 30px;
background-color: skyblue;
border-radius: 50%;
margin: 10px;
/* inline-block: 对外是行内样式, 对内是块样式 */
display: inline-block;
}
</style>
</head>
<body>
<div class="box">
<section>
<div></div>
<div></div>
<div></div>
<!-- 多项也能进行居中 -->
<!-- <div></div>
<div></div> -->
</section>
</div>
</body>
</html>
这个搞起来就有点麻烦, 但是也能, 不过要这样对比才能发现这个 flex 是真的香呀, 而且还是自适应的.
均分列布局
最常用的就是小程序底部的菜单栏, 将底部进行一个均分排列, 即便新增也是均分开显示哦.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>均分列布局</title>
<style>
.main {
/* 块盒子不写 width 就是默认浏览器 */
height: 200px;
background-color: pink;
display: flex;
/* 设置子元素均分列, 自适应 */
/* justify-content: space-around; */
/* justify-content: space-evenly; */
justify-content: space-between;
/* 可以移到底部 */
align-items: flex-end;
/* 左右留一点间距出来 */
padding: 10px 20px;
/* 保证父容器不被撑开, 设置为怪异盒模型 */
box-sizing: border-box;
}
.main div {
width: 30px;
height: 30px;
border-radius: 50%;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</body>
</html>
同样如果不用 flex 的话, 用 float
来实现就有一点麻烦啦.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>只能固定尺寸: 均分列布局</title>
<style>
.main {
height: 200px;
background-color: pink;
/* 要用宽度, float 分散 */
width: 500px;
/* 溢出则要隐藏 */
overflow: hidden;
box-sizing: border-box;
/* 左右边距 */
padding: 0 10px;
/* 子绝父相 */
position: relative;
}
.main section {
width: 800px;
position: absolute;
bottom: 10px;
}
.main div {
width: 30px;
height: 30px;
border-radius: 50%;
background-color: skyblue;
float: left;
margin-right: 120px;
}
</style>
</head>
<body>
<div class="main">
<section>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
</body>
</html>
可以看到这个用浮动 + 定位来实现就要计算宽度, 有点麻烦, 而且还不能自适应, 果断废弃用 flex 呀.
子项分组布局
其实就是嵌套 flex. 比如有3个块要横向排列, 一个在左边, 另外两个靠右边, 中间空出来这种效果.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>子项分组布局</title>
<style>
.main {
height: 200px;
background-color: pink;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 右边, 即 main 下的第二个兄弟, 也进行 flex 布局 */
.main div:nth-of-type(2) {
display: flex;
/* 留一点间隙 */
margin-left: 10px;
}
.main .box {
width: 50px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<!-- 外层容器用 flex -->
<div class="main">
<div class="box">1</div>
<!-- 子项也进行 flex -->
<div>
<div class="box">2</div>
<div class="box">3</div>
</div>
</div>
</body>
</html>
这个核心在于在 html 的部分进行嵌套和包裹, 再用 flex , 能够实现效果, 但是有点麻烦. 其实有个更为简单的办法, 是通过 margin-right: auto;
Tips: 当父容器布局为 flex 时, 子项用 margin-right: auto 会将右边的元素直接挤压到右侧, 贼好用
关于 flex 父容器的相关设置和常用的布局就基本到这啦.