Flexbox 之旅:掌握 CSS 弹性布局的核心技巧
一、前言
随着浏览器支持度越来越高,现在很多框架和应用布局都大量采用了 Flexbox 弹性布局
,所以掌握 Flexbox 弹性布局
对我们前端开发来说非常重要,刚好前几天有掘友要求写一篇关于css的文章,经过几天的思考总结,我认为写一篇关于Flexbox 弹性布局
的文章还是很有必要,一方面是巩固下自己的基础知识,一方面是可以帮助到有需要的朋友,也是一件快乐的事情。
Flexbox的基本概念
Flexbox 弹性布局
是CSS3中引入的一种一维布局模型,用于更有效地在容器中分配空间和对齐内容。Flexbox布局
能够解决传统布局方式在实现复杂布局时的种种问题,使得布局更加灵活和高效。
在 Flexbox弹性布局 中,有一下几个重要的概念
- 容器(Flex Container) :包含子元素的父元素,通过设置
display: flex
为块级容器
或display: inline-flex
为行内容器
将其转换为 Flex 容器。 - 项目(Flex Item) :Flex 容器的直接子元素。
- 主轴(Main Axis) :项目排列的主要方向,可以是
水平
或垂直
,我们大部分情况基本都是水平方向。 - 交叉轴(Cross Axis) :与
主轴
垂直的方向。 - start end
主轴
和交叉抽
的开始和结束点。 - 弹性空间:当所有
子元素
的尺寸加起来不足以填满容器时,剩余的空间。
简单用图示意一下
需要注意的是下面图主轴
默认水平方向,但实际应用中我们可以用direction
属性改变主轴
的方向,也就是下面示意图中主轴
和交叉轴
可以交换 ,start
和end
也可以交换,理解这一点非常重要。
二、Flexbox父元素容器属性
Flexbox
父元素属性一共有下面六个:
flex-direction
定义项目的排列方向,也就是上面说的改变方向。flex-wrap
控制项目是否换行。justify-content
定义项目在主轴上的对齐方式。align-items
定义项目在交叉轴上的对齐方式。align-content
定义多根轴线的对齐方式,作用于有多根轴线的情况。flex-flow
用于同时设置flex-direction
和flex-wrap
,我认为这个不是很常见不建议使用,知道有这个属性就好。
一. flex-direction 定义项目的排列方向
flex-direction
属性一共有下面4个
-
row
:默认值,主轴为水平方向,项目从左到右排列。 -
row-reverse
:主轴为水平方向,项目从右到左排列。 -
column
:主轴为垂直方向,项目从上到下排列。 -
column-reverse
:主轴为垂直方向,项目从下到上排列。
先看看默认 row
效果
<template>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
flex-direction:row; /** 默认row */
}
.item{
width: 200px;
background-color: antiquewhite;
height: 100px;
margin: 10px;
text-align: center;
}
</style>
运行效果如下:主轴为水平方向,项目从左到右排列。
注意:我这里是为了方便查看具体位置所以子元素加了 margin
属性
看看row-reverse
效果
其他代码和上面相同所以我省略了,修改父元素 flex-direction
属性。
...
.container{
display: flex;
background-color: aquamarine;
flex-direction:row-reverse; /** 修改了这个地方 */
}
...
运行效果如下:主轴为水平方向,项目从右到左排列。
看看column
效果
...
.container{
display: flex;
background-color: aquamarine;
flex-direction:column; /** 修改了这个地方 */
}
...
运行效果如下:主轴为垂直方向,项目从上到下排列。
注意:这里高度站满了是因为我们没有设置父元素高度,如果我们设置了高度,且父元素大于子元素高度以及留空之和的话,那么下面会留出空余空间,否则会占满且压缩子元素高度。有兴趣的朋友可以自己亲手尝试一下有助于你深刻理解弹性的含义。
看看column-reverse
效果
...
.container{
display: flex;
background-color: aquamarine;
flex-direction:column-reverse; /** 修改了这个地方 */
}
...
运行效果如下:主轴为垂直方向,项目从下到上排列。
二. flex-wrap 控制项目是否换行 使用比较频繁,建议重点掌握
注意因为篇幅有限所以下面几个例子都是采用的主轴默认水平方向
,如果掌握了上面内容其实就可以看出主轴在水平方向和垂直方向
原理是差不多的,唯一需要注意的是如果是主轴设置垂直方向需要设置父元素高度才会生效
计算也是按子元素高度计算。自己也可以用 垂直方向试一试
加深理解。
flex-wrap
属性一共有下面三个:
-
nowrap
:默认值,不换行。 -
wrap
:换行,第一行在上方。 -
wrap-reverse
:换行,第一行在下方。
先看看默认nowrap
效果
<template>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
flex-direction:row; /** 默认row */
flex-wrap: nowrap; /** 默认nowrap */
}
.item{
width: 200px;
background-color: antiquewhite;
height: 100px;
margin: 10px;
text-align: center;
}
</style>
运行效果如下:可以看到子元素没有其他特殊属性影响的话,父元素默认不允许换行,如果子元素宽度之和超过父元素宽度,子元素宽度会被压缩,以适配父元素宽度。
注意:我这里为了方便查看比较加了 margin
属性, margin
属性不会被压缩。
看看wrap
效果
其他代码和上面相同所以我省略了,修改父元素 flex-wrap
属性。
...
.container{
display: flex;
background-color: aquamarine;
flex-wrap: wrap; /** 修改了这里*/
}
...
运行效果如下:项目换行,第一行在上方,因为换行了所以子元素不会被压缩,当前空间不够会自动换行。 这在子元素数量未知的情况下非常有用。
看看wrap-reverse
效果
...
.container{
display: flex;
background-color: aquamarine;
flex-wrap: wrap-reverse; /** 修改了这里*/
}
...
运行效果如下: 换行,第一行在下方。乍一看和上面没有什么区别,请仔细看数字的变化。换句话说就是从底部往顶部排,建议自己多创建一些子元素实践一下。
三. justify-content 定义项目在主轴上的对齐方式 使用比较频繁,建议重点掌握
注意因为篇幅有限所以下面几个例子都是采用的主轴默认水平方向
。
justify-content
属性一共有下面三个:
-
flex-start
:默认值,项目从头部开始排列。 -
flex-end
:项目从尾部开始排列。 -
center
:项目居中排列。 -
space-between
:项目两端对齐,项目之间的间隔相等。 -
space-around
:项目两端的间隔相等,项目之间的间隔也相等。 -
space-evenly
:项目之间的间隔相等,项目和容器边缘的间隔也相等。
先看看默认flex-start
效果
<template>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
justify-content: flex-start;
}
.item{
width: 200px;
background-color: antiquewhite;
height: 100px;
margin: 10px;
text-align: center;
}
</style>
运行效果如下:可以看到子元素按照主轴方向从头部开始排列,所以这个属性受到flex-direction
影响特别大。建议自己多修改flex-direction
属性,对比运行效果,加深理解。
看看flex-end
效果
...
.container{
display: flex;
background-color: aquamarine;
justify-content: flex-end;
}
...
运行效果如下:项目从尾部开始排列,注意数字的顺序 。
看看center
效果
...
.container{
display: flex;
background-color: aquamarine;
justify-content: center;
}
...
运行效果如下:项目居中排列。
看看space-between
效果
...
.container{
display: flex;
background-color: aquamarine;
justify-content: space-between;
}
...
运行效果如下:项目两端对齐,项目之间的间隔相等。
这里需要注意:这里的计算当子元素间距大于maring
他会把 margin
加到子元素的宽高中进行计算,否则会以margin
为保底压缩子元素大小 。
看看space-around
效果
...
.container{
display: flex;
background-color: aquamarine;
justify-content: space-around;
}
...
运行效果如下:项目两端的间隔相等,项目之间的间隔也相等。也就是项目之间的间距是项目和父元素之间的间距的2倍。
这里需要注意:这里的计算当子元素间距大于maring
他会把 margin
加到子元素的宽高中进行计算,否则会以margin
为保底压缩子元素大小 。
看看space-evenly
效果
...
.container{
display: flex;
background-color: aquamarine;
justify-content: space-evenly;
}
...
运行效果如下:项目之间的间隔相等,项目和容器边缘的间隔也相等。
这里需要注意:这里的计算当子元素间距大于maring
他会把 margin
加到子元素的宽高中进行计算,否则会以margin
为保底压缩子元素大小 。
这里是去掉子元素margin
属性的效果
这里是加上子元素
margin
属性的效果
四. align-items 定义项目在交叉轴上的对齐方式 使用比较频繁,建议重点掌握
align-items
属性一共有下面五个:
-
stretch
:默认值,项目拉伸以适应容器。 -
flex-start
:项目在交叉轴的起点对齐。 -
flex-end
:项目在交叉轴的终点对齐。 -
center
:项目在交叉轴上居中。 -
baseline
:项目的基线对齐。
先看看默认stretch
效果 项目拉伸以适应容器
注意因为篇幅有限所以下面几个例子都是采用的主轴默认水平方向
。
<template>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item" style="height: 200px;">4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
align-items: stretch;
height: 300px;
}
.item{
width: 200px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
注意 上面代码我去掉了子元素 1,2,3
的高度,给父元素
加上了高度300px,单独给子元素4
设置了高度200px;
运行效果如下:
看看flex-start
效果 项目在交叉轴的起点对齐。
<template>
<div class="container">
<div class="item" style="height: 50px;">1</div>
<div class="item" style="height: 100px;">2</div>
<div class="item" style="height: 150px;">3</div>
<div class="item" style="height: 200px;">4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
align-items: flex-start;
}
.item{
width: 200px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
注意 为了方便直观对比效果,我给每个子元素都设置了不同的高度。
运行效果如下:
看看flex-end
效果 项目在交叉轴的起点对齐。
其他代码没什么变化,只修改了 align-items
属性
...
.container{
display: flex;
background-color: aquamarine;
align-items: flex-end;/**修改这里 */
}
...
</style>
运行效果如下:
看看center
效果 项目在交叉轴的起点对齐。
...
.container{
display: flex;
background-color: aquamarine;
align-items: center;/**修改这里 */
}
...
</style>
运行效果如下:
看看baseline
效果 项目的基线对齐
这个基线可能不是特别好理解,通俗一点讲就是根据它们内部文本的基线进行对齐,而不是顶部对齐或底部对齐。
重点讲一下使用场景:align-items: baseline
常用于当你希望多个行内元素(如文本、图标等)在不同高度的父容器中对齐时。例如,当你有一个文本段落和一个图标时,使用 align-items: baseline
可以确保图标和文本的底部对齐,而不是图标在文本的顶部或中间。
<template>
<div class="container">
<div class="item" style="height: 50px;">1</div>
<div class="item" style="height: 100px;">2</div>
<div class="item" style="height: 150px;"></div>
<div class="item" style="height: 200px;">4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
align-items: baseline;/**修改这里 */
}
.item{
width: 200px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
注意 为了方便直观对比效果,我把第三个子元素的文字去掉。
运行效果如下:
五. align-content 定义多根轴线的对齐方式,作用于有多根轴线的情况。
特别注意 如果项目只有一根轴线,该属性不起作用,怎么理解多根轴线呢,简单来说其实就是,是否允许项目换行 flex-wrap
当这个属性为nowrap
时 align-content
属性不会生效。所以下面例子我都会以默认水平轴和项目换行
举例。
其实仔细对比 不难发现 align-content
和 justify-content
的作用有异曲同工之妙,只是他们作用轴和使用场景不一样,align-content
针对的是子元素换行多轴的场景
,justify-content
是只针对主轴
的对齐方式。
align-content
有
-
stretch
:默认值,轴线填满整个容器。 -
flex-start
:轴线在交叉轴的起点对齐。 -
flex-end
:轴线在交叉轴的终点对齐。 -
center
:轴线在交叉轴上居中。 -
space-between
:轴线两端对齐,轴线之间的间隔相等。 -
space-around
:轴线两端的间隔相等,轴线之间的间隔也相等。 -
space-evenly
:轴线之间的间隔相等,轴线和容器边缘的间隔也相等。
先看看默认stretch
效果 轴线填满整个容器
<template>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
</template>
<style>
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: stretch;
}
.item{
width: 200px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
这里我 设置了父元素高度700px,子元素没有设置,运行效果如下:可以看到子元素会占满父元素
这里我 设置了父元素高度700px,当给子元素也设置高度200px,运行效果如下:可以看到子元素会想办法站满 只是自己能力不够。
看看flex-start
效果 轴线在交叉轴的起点对齐
其他代码没什么变化,主要是父容器和子元素设置高度,修改 align-content
...
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: flex-start;
}
...
运行效果如下:
看看flex-end
效果 轴线在交叉轴的终点对齐
...
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: flex-end;
}
...
运行效果如下: 注意子元素顺序,这里要理解对齐方式和排列方式的区别
看看center
效果 轴线在交叉轴上居中
...
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: center;
}
...
运行效果如下:
看看space-between
效果 轴线两端对齐,轴线之间的间隔相等
...
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: space-between;
}
...
运行效果如下:
看看space-around
效果 轴线两端的间隔相等,轴线之间的间隔也相等。
...
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: space-around;
}
...
运行效果如下:
看看space-evenly
效果 轴线之间的间隔相等,轴线和容器边缘的间隔也相等。
...
.container{
display: flex;
height: 700px;
background-color: aquamarine;
flex-direction: row; /*默认水平轴从左到右*/
flex-wrap: wrap; /*允许换行*/
align-content: space-evenly;
}
...
运行效果如下:
三、项目(子元素)属性
Flexbox
子元素属性一共有下面六个:
order
定义项目的排列顺序,数值越小,排列越靠前,默认为0。flex-grow
定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。flex-shrink
定义项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。flex-basis
定义在分配多余空间之前,项目占据的主轴空间,默认为auto
,即项目本身的大小。flex
是flex-grow
,flex-shrink
和flex-basis
的简写,默认值为0 1 auto
。align-self
允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性,默认值为auto
,即继承父元素的align-items
属性。
一、order 定义项目的排列顺序
这个简单就是给子元素排序,数字越小越前面。
<template>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
}
.item{
width: 200px;
height: 100px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
运行效果如下:为了方便区分我给子元素4设置了order:-1;background-color:red
二、flex-grow 定义项目的放大比例
通俗一点讲就是子元素会按照比例占满剩余空间,数值越大占比越多,所以前提条件是夫容器有剩余空间
,否则不会生效。
<template>
<div class="container">
<div class="item" style="background-color: red;flex-grow:1">1</div>
<div class="item" style="background-color: blue;flex-grow:2">2</div>
<div class="item">3</div>
<div class="item" >4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
}
.item{
width: 100px;
height: 100px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
运行效果如下:为了方便区分我给子元素1设置了background-color: red;flex-grow:1;
给子元素2设置了background-color: blue;flex-grow:2
这里需要强调一下是按比例占据剩余空间
,所以要看占比是需要除开元素本身原来的大小。
剩余空间占据示意图:下面黄色框圈出来的才是按比例占据的空间。
三、flex-shrink 定义项目的缩小比例
和上面 flex-grow
相反 flex-shrink
是空间不足时缩放子元素,数值越大缩放越多,默认为1,如果为0则不进行缩放。
<template>
<div class="container">
<div class="item" style="background-color: red;flex-shrink:2">1</div>
<div class="item" style="background-color: blue;flex-shrink:0">2</div>
<div class="item">3</div>
<div class="item" >4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
}
.item{
width: 300px;
height: 100px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
运行效果 如下 为了方便区分我给子元素1设置了background-color: red;flex-shrink:2
给子元素2设置了background-color: blue;flex-shrink:0
,这里也需要注意缩放占比是需要除开元素本身原来的大小。
四、flex-basis 定义在分配多余空间之前,项目占据的主轴空间。
这个理解起来其实不是特别顺畅,换一个思路其实就是相当于重新设置了子元素的大小。
在主轴为水平方向时,flex-basis: 300px;和width:300px
可以理解为等价的。
<template>
<div class="container">
<div class="item" style="background-color: red;flex-basis: 600px;">1</div>
<div class="item" >2</div>
<div class="item">3</div>
<div class="item" >4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
}
.item{
width: 200px;
height: 100px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
运行效果 如下 为了方便区分我给子元素1设置了background-color: red;flex-basis: 600px;
五、flex 是flex-grow
,flex-shrink
和flex-basis
的简写。
flex
默认值为0 1 auto
,后面2个属性属于可选。
有几个常用属性需要注意
flex:none
元素不会放大也不会缩小。
<div class="container">
<div class="item" style="background-color: red;flex:none">1</div>
<div class="item" >2</div>
<div class="item">3</div>
<div class="item" >4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
}
.item{
width: 200px;
height: 100px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
运行效果如下:子元素1 永远不会放大缩小。
flex:0
项目宽度设置的宽度失效,最终尺寸表现为最小内容宽度。 运行效果如下:子元素1 只有内容宽度。
flex:auto
子元素可以放大缩小,但在剩余空间不足时会优先最大化内容尺寸。
<template>
<div class="container">
<div class="item" style="background-color: red;flex:auto">
<div style="width: 400px;">1</div>
</div>
<div class="item" > 2 </div>
<div class="item">3</div>
<div class="item" >4</div>
</div>
</template>
<style>
.container{
display: flex;
background-color: aquamarine;
}
.item{
width: 300px;
height: 100px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
flex:auto;
}
</style>
注意 为了方便对比我这里给资源1添加了子元素,且设置了宽度400px,给每个子元素都设置了flex:auto
;
运行效果如下:子元素1宽度大于400px。
-
flex:1
子元素也可以放大缩小,但在剩余空间不足时会优先最小化内容尺寸。flex:1
和flex:auto
差不多,只是他会优先最小化内容尺寸运行效果如下:子元素1宽度刚好等于400px。
六、align-self 允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性
align-self
属性 和 父元素的align-items
属性保持一致,它单独左右与子元素自己本身。
<template>
<div class="container">
<div class="item" style=" height: 50px;"> 1 </div>
<div class="item" style="height: 100px;align-self: flex-end;">2 </div>
<div class="item" style="height: 150px;">3</div>
<div class="item" style="height: 200px;">4</div>
</div>
</template>
<style>
.container{
display: flex;
height: 300px;
background-color: aquamarine;
}
.item{
width: 200px;
background-color: antiquewhite;
margin: 10px;
text-align: center;
}
</style>
给子元素2 设置了属性 align-self: flex-end;
运行效果如下
如果去掉子元素2 align-self
属性 运行效果如下
总结
通过上面逐个属性详细解释并配上具体的例子和图解,相信你能更好地理解Flexbox布局的强大和灵活性,掌握Flexbox的各种属性和使用方法,可以更加高效地实现各种复杂的布局需求。
内容有点多建议收藏后跟着例子动手实践学习一下。
转载自:https://juejin.cn/post/7392530614132506636