接触flex布局也很长时间了,大多用它来处理一些水平、垂直对齐的场景,今天看官方规范文档,才发现flex还有很多有用且强大的特性,看完觉得收益匪浅,有必要总结分享出来。
这是我参与更文挑战的第6天,活动详情查看: 更文挑战
定义
我们都知道块布局、行内布局、表格布局、定位布局是常用的css布局,它们能满足web项目中的大部分业务场景。
然而随着web应用从页面向app的过渡,那些用来处理文档、页面式的布局方式在应对web App时显的捉襟见肘。
因此w3c 引入flex布局,它非常擅长处理容器内元素的排列和对齐,并且支持指定排列方向。
所以flex布局是一种新的布局模型,用来处理复杂的web应用或者页面的布局。
关于flex的几个概念
flex容器类型
我们通过给一个元素设置display:flex|inline-flex来将该元素声明为一个flex容器,该flex容器内的子元素称为flex item。
声明一个flex容器会生成一个新的flex布局上下文,在这个布局上下文里:
- 子节点的浮动效果会被忽略
- 绝对定位元素不会参与flex布局(flex布局不会影响绝对定位子元素,因为它已经独立于文档流了)。
flex容器内的子元素称为flex item。
flex表示块级容器、而inline-flex表示行内容器,两者的区别是:
- 第一个独占一行
- 另一个表现类似于行内块。
主轴和交叉轴(次轴)
我们可以通过flex-direction指定一个flex容器的流的方向,其flex item将遵从这个方向,这个方向上的轴我们称为主轴(main axis),相对主轴的次轴我们称之为交叉轴(cross axis),主轴的尺寸称为main size,交叉轴的尺寸称为cross size。
另:主轴可以水平轴也可以是垂直轴,同样交叉轴亦然。主轴和交叉轴永远是交叉关系。
先说"弹性"
我们知道flex布局的中文叫“弹性布局“,弹性就意味着可以延伸也可以收缩。
要实现flex item的弹性效果,还需要借助三个属性:
- flex-grow:表示flex item的增长因子。决定了某个flex item相对于其他flex item如何分配剩余空间,默认为0。
- flex-shrink:表示flex item的收缩因子。当容器尺寸不够容纳所有的flex item时,决定了某个flex item相对于其他flex item如何收缩自身空间,默认为1。注意:flex item不会收缩到0
- flex-basis:flex的初始基础尺寸。默认为auto(如果同时设置了with、height属性和flex-basis非auto的值,那么flex-basis具有更高的优先级)。
另:如果flex-basis设置为0表示该元素的初始尺寸为minimum-size(最小尺寸):
- 对于内容为英文的盒子,最小尺寸为整个句子中最长的单词所占据的宽度
- 对于中文,最小尺寸为单个字占据的宽度
以上三个属性需要设置给flex item元素,也可以简写为flex:flex-grow flex-shrink flex-basis;
flex item的默认弹性设置为:flex:0 1 auto;,表示不延伸、等比例收缩。
再讲排列方向和对齐
我们已经知道了通过flex-direction来指定flex主轴上排列的方向,其实它的值有多种:
- row:水平方向,从左到右(默认值)
- column,竖直方向,从上到下
- row-reverse:水平方向,从右到左
- column-reverse:竖直方向,从下到上
所以,flex-direction只是指定了一个大概的排列方向,那么flex item具体如何对齐,仍需要通过额外的属性来指定,主要有两个方面:
- 主轴的对齐:通过
justify-content
- 交叉轴的对齐:通过
align-items(设置到flex容器上)或者align-self(设置到flex item上)。二者本质上是一样的,当需要给flex-item设置相同的对齐规则时,建议使用align-items
独立独行的内、外边距
首先,flex容器的外边距不会与flex item的外边距“合并”,也就是说没有外边距的塌陷问题。
其次,flex item各自的外边距和内边距相互独立不会互相影响。
再次,flex item内、外边距的百分比值都是相对于flex容器的width值的,无论其主轴是什么方向。
另:值为auto的外边距可以吸纳额外的有效空间,从而实现元素的布局的效果。
快速实现一个左右布局
这里利用了margin-left吸纳了额外的有效空间,从而将第二个元素推到最右边:
<style>
.container{
display: flex;
}
.right{
margin-left: auto;
}
</style>
<div class="container">
<div class="left">Left</div>
<div class="right">Right</div>
</div>
实现一个对角布局
这里利用margin-top吸纳了交叉轴的可用空间,从而将第二个元素推到了最底部:
<style>
.container{
display: flex;
width: 200px;
height: 200px;
border: 1px solid orange;
}
.item{
width: 100px;
height: 100px;
background-color: #ccc;
}
.right-bottom{
margin-top: auto;
}
</style>
<div class="container">
<div class="item">Left-Top-Corner</div>
<div class="item right-bottom">Right-Bottom-Corner</div>
</div>
使用margin:auto填充空间的优点是智能、简单、便捷。
介绍几个flex的应用场景
这里再介绍几个flex有趣的案例
不定宽的手风琴侧边栏
这里的不定宽指的是容器的宽度由不确定的内容决定。hover父菜单显示其下的子菜单,你可能很快就写出了下面的代码:
<style>
.container{
display: inline-flex;
flex-direction: column;
padding: 10px;
border: 1px solid #ccc;
}
.item{
padding: 6px 0;
}
.item:hover + .subitem{
display: block;
}
.subitem{
display: none;
}
</style>
<div class="container">
<div class="item">Home</div>
<div class="subitem">
<div>News</div>
<div>Advertisement</div>
<div>Cooperation</div>
</div>
</div>
由于我们是通过修改元素的display属性显示或隐藏子菜单,这样的切换会改变父盒子的尺寸,因此界面会明显地闪烁(重绘重排?)
我们可以借助flex item的预渲染能力,修改一下代码:
.item:hover + .subitem{
visibility: visible;
height: auto;
}
.subitem{
visibility: collapse;
height: 0;
}
这样虽然子菜单隐藏了,但是flex容器依然为它保留了布局的空间。这样子菜单显示时可以有效地避免父盒子尺寸变化带来的闪烁问题
绘制简单柱形图
直接上代码:
<style>
.container{
display: inline-flex;
align-items: flex-end;
}
.item{
width: 20px;
background-color: rgb(111, 186, 248);
margin: 0 10px;
}
.bar1{
height: 20px;
}
.bar2{
height: 30px;
}
.bar3{
height: 50px;
}
</style>
<div class="container">
<div class="item bar1"></div>
<div class="item bar2"></div>
<div class="item bar3"></div>
</div>
我们通过设置交叉轴的对齐为终点对齐,实现圆柱底部对齐。
布局聊天框
聊天框需要实现以下几个功能点:
- 聊天内容盒子尺寸不定
- 从上而下排列方向
- 一个左对齐,另一个右对齐
- 某一方可能连续发多条消息
基于以上需求,使用普通布局方式实现上述业务可能会麻烦一点,然而使用flex布局仅需要几行代码:
<style>
.container{
display: flex;
flex-direction: column;
width: 400px;
padding: 10px;
border: 2px dashed orange;
}
.item{
border-radius: 4px;
border: 1px solid #ccc;
}
.customer{
align-self: flex-start;
}
.service{
align-self: flex-end;
}
</style>
<div class="container">
<div class="item customer">
你们的软件怎么回事啊?
</div>
<div class="item service">
抱歉给您带来了不便,请问是什么问题呢?
</div>
<div class="item customer">
什么问题?
</div>
<div class="item customer">
你知道给我带来了多大的损失吗?
</div>
</div>
总结
当然,flex布局的知识不仅仅这些,还有更多精彩有趣的等待着我们发现。
我们可以对flex布局做个总结:
- 可以设置任意的流动方向(左,右,上,下)
- 可以反转方向
- 主轴可以单行或多行排列(支持折行)
- 可以根据设置“弹性”地伸缩自己的尺寸适应flex容器的大小
- 支持主轴、交叉轴的多种对齐方式
最后,由于篇幅所限,无法对flex所有的知识点都解释到,有对flex任何疑惑的小伙伴,欢迎留言讨论哦。
感谢阅读