优雅的flexbox,web布局的必然趋势
2015-01-28
1. 背景及介绍
1.1 背景
到目前为止,总共有三个版本(如下),那下边主要是根据最新版本的语法来展开讲解
- 旧版本(Old),2009版本,使用display:box
- 混合版本(Hybrid),2011年版本,使用display:flexbox
- 最新版本(Modern),使用display:flex
1.2 介绍
CSS2.1总共定义了四种布局模式:
- block布局:为文档(document)布局模式
- inline布局:为文本布局模式
- table布局:为以表格形式的2D数据的布局模式
- position布局:能够明确地定位元素的布局模式
那CSS3引入flexbox的主要思想,是让容器有能力让其子项目能够改变其width,height,甚至order,以合理的方式填充可用空间,这在不同屏幕大小和不同设备上非常实用,所以可以说,flexbox就是为如今大型或者复杂应用而设计的。
2. flexbox模型
flexbox不是一个属性,他是一个模块,该模块扩展了CSS2.1中display
属性的定义,添加了新的block-level
和inline-level
的display
类型,所以要定义一个flexbox容器,可以是一个元素display
属性值为flex
,也可以是inline-flex
.而且在flexbox模型,布局计算方式也inline
,block
不同,后两者是偏向使用书写模式的,而flexbox则是偏向使用伸缩流方向.这块介绍一下相关的术语.
伸缩容器 既然一个盒模型,首先它得有一个容器,元素display
属性值为flex
或者inline-flex
就是伸缩容器.
伸缩项目 容器里的每个子元素都是这个容器的伸缩项目
主轴(main axis) flex容器的主轴,伸缩项目(flex items)主要沿着这条轴进行排列布局
主轴起点(main-start) 主轴终点(main-end) 伸缩项目放置在flex容器内从主轴起点(main-start)向主轴终点(main-end)方向
主轴尺寸(main size) 一个伸缩项目的宽度或高度,它是在主轴维度(main dimension)里面的,且是项目的主尺寸。伸缩项目的主尺寸属性是宽度或高度属性,它是在主轴维度(main dimension)里面的。
侧轴(cross axis) 垂直于主轴称为侧轴。它的方向主要取决于主轴方向
侧轴起点(cross-start) 侧轴终点(cross-end) 伸缩行的配置从容器的侧轴起点边开始,往侧轴终点边结束
侧轴尺寸(cross size) 一个伸缩项目的宽度或高度,它是在侧轴维度(main dimension)里面的,且是项目的主尺寸。伸缩项目的侧轴尺寸属性是宽度或高度属性,它是在侧轴维度(main dimension)里面的。
3. flex容器和项目的属性
flexbox模型下的属性比较多,这块不再这里陈述,为了更快速直观地了解其下边的属性的用法,请参考下边的demo.
4. 伸缩性原理
伸缩布局的特性就是让伸缩项目具有可伸缩的能力,即其宽度或高度自动填充伸缩容器额外的空间,那么这可以用flex属性来完成.如下图,flex属性有3个值,分别代表着扩展比率,收缩比率以及伸缩基准值,当一个元素是伸缩项目时,flex属性将代替主轴长度属性决定元素的主轴长度.
那么,伸缩项目是怎么以最佳方式进行伸缩的呢?这里根据上图介绍一个伸展的例子
比如上图的伸缩容器的主轴长度是480px,下边有3个伸缩项,第二张图由于3个子项
flex-grow
都是0,所以不具有伸展性,所以它们在主轴里的宽度就是它们的flex-basis
值.再看第三张图,把它们的flex-grow
改为3,2,1之后,那么这个时候容器里边的多余空间就会按照这个比例分别分配给3个子项,每个子项增加的宽度=container_blank ×(grow/sum(grow))
,最终它们在容器占用的空间就是grow_width
+flex-basis
.再假如我们把flex-basis设为0,那么flex-grow
的比例就是它们自身空间在容器里边的比例值,而不是增长的那部分的比例.同理,收缩比例值也是类似的计算方法,但是还是稍有不同,原因是在减的时候,如果只计算赋予的
flex-shrink
值,那么很有可能最后减少的宽度比 basis 大,于是子项的宽度就变成负值。所以计算的时候得把flex-basis
也带进去,最终的公式就是shrink_width = container_blank ×(shrink×basis/sum(shrink×basis))
5. 用它能做什么呢
完美居中,等高布局,双飞翼布局...都可以用它来做 这里列几个demo,均分别用传统方法和flexbox的方式来实现,试了之后会发现,用flex来实现远比传统方法优雅简单地多.
<style type="text/css">
*{font-size: 15px;color: gray;}
.flex-wrap{
box-shadow: 0 0 5px #ccc;
padding: 8px 0 8px 0;
border-radius: 5px;
display: -webkit-flex;
display: flex;
}
.flex-left{
text-align: right;
padding-left: 10px;
line-height: 30px;
}
.flex-right{
padding-right: 10px;
text-align: right;
line-height: 30px;
}
.flex-center {
-webkit-flex: 1;
flex: 1;
border: none;
outline: none;
line-height: 30px;
margin-left: 10px;
border-bottom: 1px solid #ccc;
}
</style>
<div class="flex-wrap">
<label class="flex-left">用户名:</label>
<input class="flex-center" type="text" />
<label class="flex-right">(2-20个汉字)</label>
</div>
<style>
.flex-wrap{
width: 900px;
margin: 10px auto;
display: flex;
align-items: stretch;
}
.flex-left{
width: 200px;
background: red;
float: left;
}
.flex-right{
width: 700px;
background: yellow;
float: right;
}
</style>
<div class="flex-wrap">
<div class="flex-left">
页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/>
</div>
<div class="flex-right">
页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/> 页面内容
<br/>
</div>
</div>
浏览器支持
这里有一个神奇的现象,就是这三个版本的任意一个版本单独拿出来,浏览器对它的兼容性都不是很乐观,但是把他们混合一块用,却能看到相当不错的兼容性,除了IE比较蛋疼,几乎完美兼容其他浏览器了,这么看得话,似乎在移动端现在也还是可以尝试的.即便现在兼容性上还存在问题,但是我相信flexbox必是未来布局的趋势.