哈喽,大家好呀,我是前端理想哥,今天我们来聊聊 flex 布局。
好,主角登场。
CSS 弹性盒子模型( Flexible Box 或者 Flexbox )
先来看看它的定义:弹性布局是指通过调整其内元素的宽高,从而在任何显示设备上实现对可用显示空间最佳填充的能力。弹性容器扩展其内元素来填充可用空间,或将其收缩来避免溢出。
简单来说,弹性盒子模型,是为了你的网页可以在不同分辨率设备上自适应展示而生的一种布局方式。
弹性盒子布局主要适用于应用程序的组件及小规模的布局,而(新兴的)栅格布局则针对大规模的布局。这二者都是 CSS 工作组为在不同用户代理、不同书写模式和其他灵活性要求下的网页应用程序有更好的互操作性而做出的更广泛的努力的一部分。
现在,我们来看如何定义一个弹性盒子:
<div id="main">
<div style="background-color:coral;">A</div>
<div style="background-color:lightblue;">B</div>
<div style="background-color:khaki;">C</div>
<div style="background-color:pink;">D</div>
<div style="background-color:lightgrey;">E</div>
<div style="background-color:lightgreen;">F</div>
</div>
如果要将上面的 HTML 布局改为弹性盒子布局,该怎么办?
很简单!!
只需要设置如下:
#main{
display: flex
}
或者
#main{
display: inline-flex
}
区别在于,flex 会使弹性容器成为块级元素,而 inline-flex 会使弹性容器成为单个不可分的行内级元素。
说到这里,有人会问了,弹性容器是什么东东??? 大家先来看一张图: 对比这张图和上面的 html 代码,大家可以看到:
弹性容器(Flex container)
:指的就是包含着弹性项目的父元素,即上面的 #main 弹性项目(Flex item)
:弹性容器的每个子元素都称为弹性项目,弹性容器直接包含的文本将被包覆成匿名弹性单元。即上面的 #main div
大家再仔细观察上面的那张图,图上有个主轴和侧轴,这里又涉及到一个知识点:轴(Axis)
每个弹性框布局都包含两个轴。弹性项目沿其依次排列的那根轴称为主轴(main axis)
。垂直于主轴的那根轴称为侧轴(cross axis)
接下来我结合上面的 HTML 代码为大家讲解下怎么确定主轴和主轴上内容的显示:
使用弹性容器的 flex-derection 可以确立主轴,这个属性一共有 6 个值,接下来,我为大家一一展示:
#main{
display: flex;
width: 200px;
flex-direction:row; //默认值,水平展示
}
#main{
display: flex;
width: 200px;
flex-direction:row-reverse; //与row相同,但是以相反的顺序
}
#main{
display: flex;
width: 200px;
flex-direction:column; // 弹性项目将垂直展示
}
#main{
display: flex;
width: 200px;
flex-direction:column-reverse; // 与 column 相同,但是以相反的顺序。
}
还有两个属性,简单介绍下,就不用举例了: initial:设置该属性为它的默认值 inherit:从父元素继承该属性
确定了主轴之后,那么在主轴上弹性项目怎么分布??
我们来看一个新的属性: justify-content: 定义了在当前行上,弹性项目沿主轴如何排布。
#main {
display: flex;
width: 400px;
flex-direction: row;
justify-content: flex-start; //默认值,项目位于容器的开头
}
#main{
display: flex;
width: 400px;
flex-direction: row;
justify-content: flex-end; // 项目位于容器的结尾
}
#main{
display: flex;
width: 400px;
flex-direction: row;
justify-content: center; // 项目位于容器的中间
}
#main{
display: flex;
width: 400px;
flex-direction: row;
justify-content: space-between; // 项目位于各行之间留有空白的容器内
}
#main{
display: flex;
width: 400px;
flex-direction: row;
justify-content: space-around; // 项目位于各行之前、之间、之后都留有空白的容器内。
}
还有两个属性,简单介绍下,就不用举例了: initial:设置该属性为它的默认值 inherit:从父元素继承该属性
确定了弹性项目在主轴上是怎么排布的,接下来,再介绍下在侧轴上是怎么排布的:
#main{
display: flex;
height: 200px;
align-items: stretch; // 默认值,项目被拉伸以适应容器
}
#main{
display: flex;
height: 200px;
align-items: center; // 项目位于容器的中心
}
#main{
display: flex;
height: 200px;
align-items: flex-start; // 项目位于容器的开头
}
#main{
display: flex;
height: 200px;
align-items: flex-end; // 项目位于容器的结尾
}
#main{
display: flex;
height: 200px;
align-items: baseline; // 项目位于容器的基线上
}
还有两个属性,简单介绍下,就不用举例了: initial:设置该属性为它的默认值 inherit:从父元素继承该属性
如果我只想改变单个弹性项目的对齐方式,该怎么办?
别怕,align-self 属性来也!
align-self:定义了单个弹性项目在侧轴上应当如何对齐,这个定义会覆盖由 align-items 所确立的默认值。
还是用这个 HTML 来展示:
<div id="main">
<div class="a" style="background-color:coral;">A</div>
<div class="b" style="background-color:lightblue;">B</div>
<div class="c" style="background-color:khaki;">C</div>
<div class="d" style="background-color:pink;">D</div>
<div class="e" style="background-color:lightgrey;">E</div>
<div class="f" style="background-color:lightgreen;">F</div>
</div>
#main{
display: flex;
height: 200px;
align-items: center;
background: red;
}
#main div{
width: 40px;
}
#main .d{
align-self: auto; //默认值。元素继承了它的父容器的 align-items 属性。如果没有父容器则为 "stretch"。
}
#main .d{
align-self: stretch; //元素被拉伸以适应容器
}
#main .d{
align-self: center; //元素位于容器的中心
}
#main .d{
align-self: flex-start; //元素位于容器的开头
}
#main .d{
align-self: flex-end;
}
//元素位于容器的结尾
#main .d{
align-self: baseline; //元素位于容器的基线上
}
还有两个属性,简单介绍下,就不用举例了: initial:设置该属性为它的默认值 inherit:从父元素继承该属性
说完了弹性项目的排布,接下来,我们回看最上面那张图,再来说说,怎么确定主轴/侧轴的方向
我们先来看一个属性: flex-wrap:规定 flex 容器是单行或者多行,同时横轴的方向决定了新行堆叠的方向。
#main{
width: 200px;
height: 200px;
border: 1px solid #c3c3c3;
display:flex;
background: red;
flex-wrap: nowrap; // 默认值,规定灵活的项目不拆行或不拆列
}
#main{
width: 200px;
height: 200px;
border: 1px solid #c3c3c3;
display:flex;
background: red;
flex-wrap: wrap; // 默认值,规定灵活的项目在必要时拆行或拆列
}
#main{
width: 200px;
height: 200px;
border: 1px solid #c3c3c3;
display:flex;
background: red;
flex-wrap: wrap-reverse; // 规定灵活的项目在必要的时候拆行或拆列,但是以相反的顺序。
}
还有两个属性,简单介绍下,就不用举例了: initial:设置该属性为它的默认值 inherit:从父元素继承该属性
order: 属性将元素与序号关联起来,以此决定哪些元素先出现
<div id="main">
<div class="a" style="background-color:coral;">A</div>
<div class="b" style="background-color:lightblue;">B</div>
<div class="c" style="background-color:khaki;">C</div>
<div class="d" style="background-color:pink;">D</div>
<div class="e" style="background-color:lightgrey;">E</div>
<div class="f" style="background-color:lightgreen;">F</div>
</div>
.a{
order: 6;
-webkit-order: 6;
}
.b{
order: 5;
-webkit-order: 5;
}
.c{
order: 4;
-webkit-order: 4;
}
.d{
order: 3;
-webkit-order: 3;
}
.e{
order: 2;
-webkit-order: 2;
}
.f{
order: 1;
-webkit-order: 1;
}
flex-flow:是 flex-direction 和 flex-wrap 属性的简写,决定弹性项目如何排布。
对于行(Line)中来说,根据 flex-wrap 属性,弹性项目可以排布在单个行或多个行中。此属性控制侧轴的方向和新行排列的方向
我们确定了弹性容器的主轴与侧轴,弹性项目的宽和高,怎么来确定对应的主轴尺寸和侧轴尺寸???
(1) 可以使用 min-height 和 min-width 来确定,这两个的初始值都是 0
(2) flex 属性是 flex-grow、flex-shrink 和 flex-basis 的简写,描述弹性项目的整体伸缩性。
接下来,我们逐一看看这三个新的属性
flex-grow: 用于设置或检索弹性盒的扩展比率
#main{
width: 500px;
height: 200px;
border: 1px solid #c3c3c3;
display:flex;
background: red;
}
#main div{
width: 40px;
}
.a{
flex-grow: 2;
}
.b{
flex-grow: 3;
}
.c{
flex-grow: 1;
}
.d{
flex-grow: 3;
}
.e{
flex-grow: 2;
}
.f{
flex-grow: 1;
}
flex-shrink: 指定了 flex 元素的收缩规则,flex 元素仅在默认宽度之和大于容器时才会发生收缩,其收缩的大小是依据 flex-shrink 的值
<p>div 总宽度为 500px, flex-basic 为 120px。</p>
<p>A, B, C 设置 flex-shrink:1。 D , E 设置为 flex-shrink:2</p>
<p>D , E 宽度与 A, B, C 不同</p>
<div id="content">
<div class="box" style="background-color:red;">A</div>
<div class="box" style="background-color:lightblue;">B</div>
<div class="box" style="background-color:yellow;">C</div>
<div class="box1" style="background-color:brown;">D</div>
<div class="box1" style="background-color:lightgreen;">E</div>
</div>
flex-shrink 的默认值为 1,如果没有显示定义该属性,将会自动按照默认值 1 在所有因子相加之后计算比率来进行空间收缩。 本例中 A、B、C 显式定义了 flex-shrink 为 1,D、E 定义了 flex-shrink 为 2,所以计算出来总共将剩余空间分成了 7 份,其中 A、B、C 占 1 份,D、E 占 2 份,即 1:1:1:2:2 我们可以看到父容器定义为 500px,子项被定义为 120px,子项相加之后即为 600 px,超出父容器 100px。那么超出的 100px 需要被 A、B、C、D、E 消化 通过收缩因子,所以加权综合可得 1001+100_1+100_1+100_2+100_2=700px
于是我们可以计算 A、B、C、D、E 将被移除的溢出量是多少: A 被移除溢出量:(100_1/700)_100,即约等于 14px B 被移除溢出量:(100_1/700)_100,即约等于 14px C 被移除溢出量:(100_1/700)_100,即约等于 14px D 被移除溢出量:(100_2/700)_100,即约等于 28px E 被移除溢出量:(100_2/700)_100,即约等于 28px 最后 A、B、C、D、E 的实际宽度分别为:120-14=106px, 120-14=106px, 120-14=106px, 120-28=92px,120-28=92px,此外,这个宽度是包含边框的。__
flex-basis:用于设置或检索弹性盒伸缩基准值。
接下来,说几个弹性盒子的相关属性: 由于弹性盒子使用了不同的布局算法,某些属性用在弹性容器上没有意义:
- 多栏布局模块的 column-* 属性对弹性项目无效
- float 与 clear 对弹性项目无效。使用 float 将使元素的 display 属性记为 block
- vertical-align 对弹性项目的对齐方式无效。
最后,我们来看换一个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.flex
{
/* 基本样式 */
width: 350px;
height: 200px;
border: 1px solid #555;
font: 14px Arial;
/* 建立弹性框 */
display: -webkit-flex;
-webkit-flex-direction: row;
display: flex;
flex-direction: row;
}
.flex > div
{
-webkit-flex: 1 1 auto;
flex: 1 1 auto;
width: 30px; /* 让过渡表现良好。(从/到"width:auto"的过渡
至少在 Gecko 和 Webkit 上是有 bug 的。
更多信息参见 http://bugzil.la/731886 ) */
-webkit-transition: width 0.7s ease-out;
transition: width 0.7s ease-out;
}
/* colors */
.flex > div:nth-child(1){ background : #009246; }
.flex > div:nth-child(2){ background : #F1F2F1; }
.flex > div:nth-child(3){ background : #CE2B37; }
.flex > div:hover
{
width: 200px;
}
</style>
</head>
<body>
<p>Flexbox nuovo</p>
<div class="flex">
<div>uno</div>
<div>due</div>
<div>tre</div>
</div>
</body>
</html>