CSS学习-flex布局
Flex布局
Flex 布局基本概念
Flex 布局即“弹性布局”,是一个一维的布局,每次只能处理一行或一列;传统方式对于垂直居中、对齐等特殊布局比较复杂,使用 Flex 可以简单、响应式的实现各种网页布局。
Flex 容器
给一个块级元素添加:display:flex
;行内元素也可以设置 flex 容器 : display: inline-flex
;
.box {
display: flex;
}
Flex 容器的所有子元素都成为(flex item) 成员;容器有两根轴:水平方向(主轴 main-axis)和 垂直方向(交叉轴 cross-axis);每个轴在方向上都有 start 和 end,它决定了 flex 元素依次排列的方向。
效果图:
容器的属性
以下 7 个属性可以设置在容器上。
flex-direction
flex-direction 该属性决定了主轴 flex 元素的排列方向;
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
flex-wrap
flex 容器默认是不换行的;flex-wrap 该属性可以实现 flex 容器展示多行元素;
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
flex-flow
flex-flow 该属性是 flex-direction | flex-wrap 的缩写;
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
justify-content
justify-content 指定容器内主轴的对齐方式;
- space-between 均匀排列每个元素,首个元素放置于起点,末尾元素放置于终点;
- space-around 每个元素周围分配相同的空间
- space-evenly 每个元素之间的间隔相等
.box {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
效果图:
align-items
align-items 指定容器内交叉轴的对齐方式;
.box {
align-items: stretch | flex-start | flex-end | center | baseline;
}
- stretch 拉伸,如果项目中未设置高度或设为auto,将沾满整个容器的高度;即 flex 容器子项设置了高度,默认将不会拉伸高度到该行最高元素;
效果图:
align-content
align-content 当容器有多行元素时指定交叉轴多行之间的对齐方式;
.box {
align-content: stretch | flex-start | flex-end | center | space-between | space-around ;
}
效果图:
gap
gap 该属性时 row-gap 和 column-gap 的缩写;
.box {
gap: row-gap | column-gap;
}
flex 元素的属性
order
控制元素显示的顺序,数值越大排列越靠后;
.box-item {
order: 0 | <integer>
}
align-self
决定单个 flex 元素的对齐方式,可以覆盖 align-items;默认 auto 等同于父元素的 align-items 属性;
.box-item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
flex-grow
flex 元素的增长系数,以 flex-basis为基础延主轴增长填满 flex容器;默认为 0 即不增长;
.box-item {
flex-grow: <number>; /* default 0 */
}
flex-shirnk
flex 元素的缩写比列,默认为1,当父容器空间不足,该元素将缩写;
.box-item {
flex-shrink: <number>; /* default 1 */
}
flex-basis
flex 元素的宽度大小,默认值为 auto 即项目的本来大小;
.box-item {
flex-basis: <length> | auto; /* default auto */
}
flex
flex 属性是 flex-grow, flex-shrink, flex-basis 的简写;默认值 0 1 auto
;
- flex: auto 表示
1 1 auto
- flex: 1 表示
1 1 0%
表示元素宽度从0%开始增长; - flex: none 表示
0 0 auto
.box-item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
常用案例
导航
在元素外部分布空间
使用justify-content
让多余空间分布在多个元素之间或周围;
效果图:
让元素自己处理空间分布
,使用flex: auto
即flex: 1 1 auto
,所有元素在 flex-basis
的基础上自动伸缩;
效果图:
拆分导航
使用自动外边距,使得导航栏中的一组元素左对齐而另一组元素右对齐;
垂直居中
使用align-items:center
可以轻松的实现元素垂直居中;
效果图:
卡片布局将页脚推到底部
在弹性盒内使用flex: 1
即flex: 1 1 0
%,元素在 flex-basis
为 0% 的基础上伸缩。它将是唯一能伸缩的元素将在容器中占据空余空间,同时将页脚推至底部。
效果图:
媒体对象
这种模式下:当一侧具有图片,另一侧具有文本,图片可以在左边或右边;
- 设置文本内容为
flex:1
使得内容部分延伸 - 设置图片
max-width
,不设置flex-basis
的宽度为 auto 即图片本身的大小
效果图:
可以实现悬挂布局,左边一个图片容器,右边一个文本容器,交叉进行排列;
效果图:
<div class="list">
<div class="list-item">
<div class="img"></div>
<div class="description"></div>
</div>
<div class="list-item">
<div class="img"></div>
<div class="description"></div>
</div>
<div class="list-item">
<div class="img"></div>
<div class="description"></div>
</div>
</div>
.list {
display: flex;
flex-direction: column;
row-gap: 10px;
}
.list-item {
display: flex;
column-gap: 20px;
}
.list-item:nth-of-type(2n) {
flex-direction: row-reverse;
}
.img {
width: 200px;
height: 100px;
}
.description {
flex: 1;
}
表单控件
搜索框,给 input 元素设置 flex: auto
即 flex: 1 1 auto
,使得 input 元素占据内容的剩余部分,可以随着可用控件的变化增长或缩写;
效果图:
效果图:
百分比布局
某个网格的宽度为固定的百分比flex-basis
,其余网格利用 flex: 1
增长平均分配剩余空间;
效果图:
<div class="Grid">
<div class="Grid-cell u-1of4">...</div>
<div class="Grid-cell">...</div>
<div class="Grid-cell u-1of3">...</div>
</div>
.Grid {
display: flex;
}
.Grid-cell {
flex: 1;
}
.Grid-cell.u-full {
flex: 0 0 100%;
}
.Grid-cell.u-1of2 {
flex: 0 0 50%;
}
.Grid-cell.u-1of3 {
flex: 0 0 33.3333%;
}
.Grid-cell.u-1of4 {
flex: 0 0 25%;
}
圣杯布局
圣杯布局 页面从上到下分为三个部分,页面从左到右分为3个部分,其中上下和左右两栏固定,中间自适应内容大小;
传统方式实现方法:
- 左右float,中间margin
- 左右absolute定位,中间margin左右两边的容器距离
- 都使用float, 先写中间部分,左右两边用负margin
效果图:
flex实现圣杯布局
<body class="HolyGrail">
<header>...</header>
<div class="HolyGrail-body">
<main class="HolyGrail-content">...</main>
<nav class="HolyGrail-nav">...</nav>
<aside class="HolyGrail-ads">...</aside>
</div>
<footer>...</footer>
</body>
.HolyGrail {
display: flex;
min-height: 100vh;
flex-direction: column;
}
header,
footer {
flex: 1;
}
.HolyGrail-body {
display: flex;
flex: 1;
}
.HolyGrail-content {
flex: 1;
}
.HolyGrail-nav, .HolyGrail-ads {
/* 两个边栏的宽度设为12em */
flex: 0 0 12em;
}
.HolyGrail-nav {
/* 导航放到最左边 */
order: -1;
}
当在小屏幕下使用媒体查询来调整 flex 容器内容排列:
@media (max-width: 768px) {
.HolyGrail-body {
flex-direction: column;
flex: 1;
}
.HolyGrail-nav,
.HolyGrail-ads,
.HolyGrail-content {
flex: auto;
}
}
固定底栏
有时候网页内容不足没有满足一屏高度,导致底部上升到页面中间,可以设置页面容器min-height: 100vh
保持整屏高度,页面内容使用flex:1
增长;
效果图:
<body class="Site">
<header>...</header>
<main class="Site-content">...</main>
<footer>...</footer>
</body>
.Site {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.Site-content {
flex: 1;
}
实战案例
小米商城固定底部导航栏
position: fixed;
固定定位可以让元素固定在页面的某个位置(脱离文档流)margin-top: -1px;
负边距可以解决重复边框问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>小米固定导航栏</title>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
background-color: #eee;
font-size: 16px;
}
ul {
list-style: none;
}
a {
color: #777;
text-decoration: none;
}
.nav-fixed {
position: fixed;
bottom: 70px;
right: 20px;
}
.nav-box {
display: flex;
flex-direction: column;
}
.nav-item {
padding: 20px 10px;
border: 1px solid #f5f5f5;
background-color: #fff;
/* 解决边框重复问题 */
margin-top: -1px;
}
.nav-item a {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
row-gap: 10px;
}
.nav-item a:hover {
color: coral;
}
.nav-item img {
width: 30px;
height: 30px;
}
.item-mgtop {
margin-top: 20px;
}
</style>
</head>
<body>
<div class="nav-fixed">
<ul class="nav-box">
<li class="nav-item">
<a href="#">
<img
src="https://i8.mifile.cn/b2c-mimall-media/98a23aae70f25798192693f21c4d4039.png"
alt=""
/>
<span>手机APP</span>
</a>
</li>
<li class="nav-item">
<a href="#">
<img
src="https://i8.mifile.cn/b2c-mimall-media/98a23aae70f25798192693f21c4d4039.png"
alt=""
/>
<span>手机APP</span>
</a>
</li>
<li class="nav-item">
<a href="#">
<img
src="https://i8.mifile.cn/b2c-mimall-media/98a23aae70f25798192693f21c4d4039.png"
alt=""
/>
<span>手机APP</span>
</a>
</li>
<li class="nav-item">
<a href="#">
<img
src="https://i8.mifile.cn/b2c-mimall-media/98a23aae70f25798192693f21c4d4039.png"
alt=""
/>
<span>手机APP</span>
</a>
</li>
<li class="nav-item">
<a href="#">
<img
src="https://i8.mifile.cn/b2c-mimall-media/98a23aae70f25798192693f21c4d4039.png"
alt=""
/>
<span>手机APP</span>
</a>
</li>
<li class="nav-item item-mgtop">
<a href="#">
<img
src="https://i8.mifile.cn/b2c-mimall-media/98a23aae70f25798192693f21c4d4039.png"
alt=""
/>
<span>手机APP</span>
</a>
</li>
</ul>
</div>
</body>
</html>
效果图:
小米商城产品列表
- 头部使用
justify-content:space-between
实现标准的导航栏; - 内部使用
flex-direction:column
来实现 flex 列容器;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>小米card列表</title>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
body {
background-color: #eee;
}
img {
/* 图片填满容器 */
width: 100%;
height: 100%;
object-fit: cover;
}
.box {
max-width: 1226px;
margin: 0 auto;
}
.flex {
display: flex;
gap: 14px;
}
.flex-column {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
.box-card {
height: 300px;
width: 234px;
border: 1px solid #d7d7d7;
background-color: #fff;
}
.box-card--gray {
border: none;
background-color: #eee;
}
.box-card-sm {
background-color: #fff;
border: 1px solid #d7d7d7;
height: 143px;
}
.box-hd {
padding: 20px 0;
align-items: center;
justify-content: space-between;
}
.more-list {
gap: 20px;
}
.more-list li {
padding: 6px 0px;
}
.more-active {
color: #ff6700;
border-bottom: 2px solid #ff6700;
}
</style>
</head>
<body>
<div class="box">
<div class="box-hd flex">
<h4 class="box-title">智能家居</h4>
<ul class="more-list flex">
<li class="more-active">小爱音响</li>
<li>门锁门铃</li>
<li>路由器</li>
<li>智能设备</li>
</ul>
</div>
<div class="box-bd flex">
<div class="box-left flex flex-column">
<div class="box-card">
<img
src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/ec383d223d9f38f442268df684c526f6.png?thumb=1&w=234&h=300&f=webp&q=90"
alt=""
/>
</div>
<div class="box-card"></div>
</div>
<div class="box-right flex flex-wrap">
<div class="box-card"></div>
<div class="box-card"></div>
<div class="box-card"></div>
<div class="box-card"></div>
<div class="box-card"></div>
<div class="box-card"></div>
<div class="box-card"></div>
<div class="box-card box-card--gray flex flex-column">
<div class="box-card-sm"></div>
<div class="box-card-sm"></div>
</div>
</div>
</div>
</div>
</body>
</html>
效果图:
总结
使用 flex 布局可以响应式的进行布局,它能使得排列方式、对齐方式、空间分布都变得简单,且可以利用 flex 元素的属性可以实现各种复杂布局属性;
参考链接
转载自:https://juejin.cn/post/7379423024556539939