年前做年报活动的时候,遇到了
space-around
在ios8
上异常的问题,后来虽然加了aligin-items:center
来解决。但是flex
布局一直没有细细深究过,加上flex/box
新旧版本的问题,着实让人有点晕。
是时候,来清算下了。先上张图,看下兼容性:
由注释可以看到:
ie一如既往的表现稳定,ie8/ie9不支持
flex
布局。ie10仅支持旧的语法,ie11支持flex
。但是这两个版本由诸多bug。另外在安卓4.3上有些bug。
考虑今天的情况,其实最起码移动端使用没有大问题了。如果能兼顾新老版本则ie10也是可以尝试的。那什么是老版本呢?什么又是新版本?
新老版本概述
参考大漠的“老”的Flexbox和“新”的Flexbox,准确来说是老中新三个版本:
- 老版本。2009年的版本,主要是
display:box
- 中版本。2011年的版本,主要是
display:flexbox
- 新版本。2013年的版本,主要是
display:flex
一下子就明白了,就是从box
到flex
的进化过程。
属性与实践
flex/inline-flex
表示盒子是一个伸缩容器,直接子元素表示为伸缩项目。写法为:
{
display:flex; //inline-flex
}
但是由于老版本及浏览器的兼容性问题,大漠推荐需要如下写:
{
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 已经和之前的兼容性图对上了 */
display: -webkit-flex; /* NEW - Chrome */
display: flex;
}
现在咱们写一个试试:
//html
<div class="flex-container">
<div class='left'>这是left</div>
<div class='mid'>这是居中</div>
<div class='right'>这是right</div>
</div>
//css
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
.left{
background: #ccc;
}
.mid{
background: #666;
}
.right{
background: #333;
}
justify-content
照例从css参考手册上看兼容性:
因此需要带厂商的浏览器前缀,并且亲测ie10也是支持的。
在弹性布局上,横轴为main-axis
,侧轴为cross-axis
。这个justify-content
就是表示横轴上子项目的对其方式。它有五个值:
- flex-start 表示从左对齐。默认即是此值。
- flex-end 表示从右对齐。
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-justify-content:flex-end;
-moz-justify-content:flex-end;
justify-content:flex-end;
}
- center表示居中
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-justify-content:center;
-moz-justify-content:center;
justify-content:center;
}
- space-between 表示两端靠边对齐,项目之前距离等分
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-justify-content:space-between;
-moz-justify-content:space-between;
justify-content:space-between;
}
- space-around 每个子项目两侧的距离相等,所以相邻的两个子项目的间隔是最左或者最右间隔的两倍
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-justify-content:space-around;
-moz-justify-content:space-around;
justify-content:space-around;
}
上面几个属性是很过瘾,可是没有关于如何均分或者不均分的布局写法,就有点不爽了。别急,接着往下看。
flex:1
现在我们将要三等分子项目,考虑到兼容写法:
.left,.right,.mid{
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 经测试ie10 不写这段代码也行 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
同时也看出,除了外层盒子的
flex
属性,兼容性都是如此的写,为box
添加moz,webkit
,为flex
加webkit,ms,
和不加。不信接着看。
如果左侧固定占100px,中间是右侧的两倍则如下:
.mid{
-webkit-box-flex: 2; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 2; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 2; /* Chrome */
-ms-flex: 2; /* IE 10 经测试ie10 不写这段代码也行 */
flex: 2; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.right{
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 经测试ie10 不写这段代码也行 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.left{
width:100px;
}
其实,flex:1
其实是flex-grow、flex-shrink、flex-basis
的缩写。
flex-grow/flex-shrink/flex-basis
简单来说:
flex-grow 是扩展比率 flex-shrink 是收缩比率 flex-basis 是初始宽度
一看就很懵逼!没关系,慢慢来。
设置flex
相当于分别依次设置flex-grow flex-shrink flex-basis
。而他们之间的关系如下:
- 当子项目的初始宽度
flex-basis
等于容器的总宽度,则各个子项目宽度就是的初始宽度,和flex-grow flex-shrink
没半毛钱关系。
.left{
-webkit-box-flex: 3 1 200px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 3 1 200px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 3 1 200px; /* Chrome */
-ms-flex: 3 1 200px; /* IE 10 */
flex: 3 1 200px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.mid{
-webkit-box-flex: 2 2 200px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 2 2 200px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 2 2 200px; /* Chrome */
-ms-flex: 2 2 200px; /* IE 10 */
flex: 2 2 200px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.right{
-webkit-box-flex: 1 3 300px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1 3 300px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1 3 300px; /* Chrome */
-ms-flex: 1 3 300px; /* IE 10 */
flex: 1 3 300px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
2.当子项目的初始宽度flex-basis
大于容器的宽度。
.left{
-webkit-box-flex: 3 1 400px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 3 1 400px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 3 1 400px; /* Chrome */
-ms-flex: 3 1 400px; /* IE 10 */
flex: 3 1 400px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.mid{
-webkit-box-flex: 2 2 200px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 2 2 200px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 2 2 200px; /* Chrome */
-ms-flex: 2 2 200px; /* IE 10 */
flex: 2 2 200px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.right{
-webkit-box-flex: 1 3 300px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1 3 300px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1 3 300px; /* Chrome */
-ms-flex: 1 3 300px; /* IE 10 */
flex: 1 3 300px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
先看它在浏览器中表现的宽度:
第一个元素本来设置400的,怎么只有352.94px
(其他俩依次是:152.94px, 194.11px
)。
因此超过容器宽度时候,子元素相当于被压缩了,采用的是压缩率即flex-shrink
。此时先计算压缩率下的宽度加权值:
400*1 + 2*200 + 3*300 = 1700
而溢出值为:
400 + 200 + 300 - 700 = 200
那每个子项目从初始值压缩的大小为:
(flex-basis * flex-shrink / 宽度加权值) * 溢出值
这样算,三个子元素的被压缩的大小分别为:47.058px,47.058px,105.882px
. 然后使用初始值减去自己的溢出值就是上面得到的真实宽度。
这么一算,其实当元素子项目宽度和超出的时候,先得出初始宽度超过容器宽度的部分的值。然后求出根据每个子元素的压缩宽度在压缩加权宽度和的比例,这个比例也是溢出值分到子元素中应该减去的比例。
- 当子元素的初始宽度小于容器宽度。
根据大于容器宽度的逻辑反推,需要先得出容器宽度超过初始宽度的部分,此时为100px。然后求出根据每个子元素的放大宽度(flex-grow*flex-basis
)在放大加权宽度的比例。这个比例也是每个元素基于100px应该补足的值。
.left{
-webkit-box-flex: 3 1 200px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 3 1 200px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 3 1 200px; /* Chrome */
-ms-flex: 3 1 200px; /* IE 10 */
flex: 3 1 200px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.mid{
-webkit-box-flex: 2 2 200px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 2 2 200px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 2 2 200px; /* Chrome */
-ms-flex: 2 2 200px; /* IE 10 */
flex: 2 2 200px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.right{
-webkit-box-flex: 1 3 300px; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1 3 300px; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1 3 300px; /* Chrome */
-ms-flex: 1 3 300px; /* IE 10 */
flex: 1 3 300px; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
此时三个元素应该不足的宽度分为别:50px, 16.66px, 33.33px
. 来咱们验证下:
那上文的flex:1
又是啥?
flex:1 --> flex:1 1 0%;
flex:auto --> flex:1 1 auto;
flex:none --> flex: 0 0 auto;
因此,在某情况下,我们需要固定子元素的宽度,而容器宽度又是不定的,那就要使flex-grow, flex-shrink
不参与计算,那就是使用flex:none
。
box-pack
其实之前在介绍水平对齐的问题上留下了一个坑,那就是老版本的box-pack
,它基本上与justify-content
一致。至于兼容写法为:
{
-moz-box-pack:center;
-ms-flex-pack:center;
-webkit-box-pack:center;
}
其实上述写法,只有-ms-flex-pack:center
有效,也就是ie10上是有效的,其他浏览器还是要写justify-content
的。
start。与
justify-content
的值为flex-start
的值一样。end。与
justify-content
的值为flex-end
的值一样。center。与
justify-content
的值为flex-center
的值一样。justify。与
justify-content
的值为sapce-between
的值一样。
到这儿,写水平对齐的策略则需要兼顾新老语法了。
{
-webkit-justify-content:space-between;
-moz-justify-content:space-between;
justify-content:space-between;
-moz-box-pack:justify;
-ms-flex-pack:justify;
-webkit-box-pack:justify;
}
align-items/box-align
之前都是介绍的横轴的对齐,现在的的align-items
是侧轴的对齐方式,而box-align
是老语法,下面的例子将会综合的兼容写法。
- 顶端对齐,即容器顶部对齐。
align-items
的值是flex-start
,box-align
的是start
.
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items:flex-start;
-webkit-align-items:flex-start;
-moz-align-items:flex-start;
-moz-box-align:start; /* 其实不起作用 */
-ms-flex-align:start;
-webkit-box-align:start;/* 其实不起作用 */
}
.left{
background: #ccc;
height: 100px;
}
.mid{
background: #666;
height: 150px;
}
.right{
background: #333;
height: 50px;
}
- 中间对齐,即容器中心对齐。
align-items
的值是center
,box-align
的是center
.
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items:center;
-webkit-align-items:center;
-moz-align-items:center;
-moz-box-align:center; /* 其实不起作用 */
-ms-flex-align:center;
-webkit-box-align:center;/* 其实不起作用 */
}
- 底部对齐,即容器中心对齐。
align-items
的值是flex-end
,box-align
的是end
.
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items:flex-end;
-webkit-align-items:flex-end;
-moz-align-items:flex-end;
-moz-box-align:end; /* 其实不起作用 */
-ms-flex-align:end;
-webkit-box-align:end;/* 其实不起作用 */
}
- 容器基线对齐,即子元素的
line-height
对齐。align-items
的值是baseine
,box-align
的是baseline
.
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items:flex-end;
-webkit-align-items:flex-end;
-moz-align-items:flex-end;
-moz-box-align:end; /* 其实不起作用 */
-ms-flex-align:end;
-webkit-box-align:end;/* 其实不起作用 */
}
.left{
background: #ccc;
height: 100px;
line-height:100px;
}
.mid{
background: #666;
height: 150px;
line-height:100px;
}
.right{
background: #333;
height: 50px;
line-height:50px;
}
- 子元素填满父元素。
align-items
的值是stretch
,box-align
的是stretch
. 是默认值。注意的是,必须没有给子元素设定高度的时候才行。
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items:stretch;
-webkit-align-items:stretch;
-moz-align-items:stretch;
-moz-box-align:stretch; /* 其实不起作用 */
-ms-flex-align:stretch;
-webkit-box-align:stretch;/* 其实不起作用 */
}
.left{
background: #ccc;
line-height:100px;
}
.mid{
background: #666;
line-height:100px;
}
.right{
background: #333;
line-height:50px;
}
flex-wrap
控制容器是多行还是单行。MDN参考说不兼容ie10,但是ie11的模拟ie10测试时候发现ie10是可以的。但是没有真正去尝试ie10,所以不能认定就兼容。
nowrap
,不换行,默认也是这个值。
.flex-container{
width: 700px;
border:#999 solid 1px;
flex-wrap: nowrap;
-webkit-flex-wrap: nowrap;
-moz-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
.left{
background: #ccc;
width: 100px;
height: 100px;
}
.mid{
background: #666;
width: 100px;
height: 100px;
}
.right{
margin:5px 10px;
background: #333;
width: 100px;
height: 100px;
}
wrap
,换行。
.flex-container{
flex-wrap: wrap;
-webkit-flex-wrap: wrap;
-moz-flex-wrap: wrap;
-ms-flex-wrap: wrap;
}
wrap-reverse
,换行倒序。
.flex-container{
flex-wrap: wrap-reverse;
-webkit-flex-wrap: wrap-reverse;
-moz-flex-wrap: wrap-reverse;
-ms-flex-wrap: wrap-reverse;
}
align-content/flex-line-pack
wrap
介绍完,终于可以说align-content
了。因为align-content
也是用于侧轴对齐,它与align-items
的区别是,align-items
表示每一行对齐,而align-content
表示整个容器侧轴对齐情况。
之前还存在过一个兼容版本flex-line-pack
。主要针对兼容ie10.
需要注意的是,只有有多行并且容器高度大于子元素高度的情况下,align-content
才有效果。
- 子元素撑满容器。此为默认值。
align-content
的值为stretch
,flex-line-pack
的值为stretch
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
flex-wrap: wrap;
-webkit-flex-wrap: wrap;
-moz-flex-wrap: wrap;
-ms-flex-wrap: wrap;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-align-content:stretch;
-moz-align-content:stretch;
align-content:stretch;
-ms-flex-line-pack:center;
}
.left{
background: #ccc;
width: 100px;
}
.mid{
background: #666;
width: 100px;
}
.right{
margin: 5px 10px;
background: #333;
width: 100px;
}
- 顶部对齐。
align-content
的值为flex-start
,flex-line-pack
的值为start
{
-webkit-align-content:flex-start;
-moz-align-content:flex-start;
align-content:flex-start;
-ms-flex-line-pack:start;
}
- 底部对齐。
align-content
的值为flex-end
,flex-line-pack
的值为end
{
-webkit-align-content:flex-end;
-moz-align-content:flex-end;
align-content:flex-end;
-ms-flex-line-pack:end;
}
- 剧中对齐。
align-content
的值为center
,flex-line-pack
的值为center
{
-webkit-align-content:center;
-moz-align-content:center;
align-content:center;
-ms-flex-line-pack:center;
}
- 两端对齐。
align-content
的值为space-between
,flex-line-pack
的值为justify
{
-webkit-align-content:space-between;
-moz-align-content:space-between;
align-content:space-between;
-ms-flex-line-pack:justify;
}
- 分散对齐。
align-content
的值为space-aorund
,flex-line-pack
的值为distribute
{
-webkit-align-content:space-aorund;
-moz-align-content:space-aorund;
align-content:space-aorund;
-ms-flex-line-pack:justify;
}
flex-dirction/box-orient/box-direction
就名字猜测分布是新/老/过度语法。用于控制子元素的顺序。
- 以行显示。
flex-dirction
的值是row
,box-orient
的值是horizontal
.
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-moz-box-orient:horizontal;
-webkit-box-orient:horizontal;
-moz-flex-direction:row;
-webkit-flex-direction:row;
-ms-flex-direction:row;
flex-direction:row;
}
- 以行倒序显示。
flex-dirction
的值是row-reverse
,box-orient
的值是horizontal
但是需要配合box-direction:reverse
. (并未测试出box-orient的效果)
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-moz-box-orient:horizontal;
-webkit-box-orient:horizontal;
-moz-box-direction:reverse;
-webkit-box-direction:reverse;
-moz-flex-direction:row-reverse;
-webkit-flex-direction:row-reverse;
-ms-flex-direction:row-reverse;
flex-direction:row-reverse;
}
- 以列显示。
flex-dirction
的值是column
,box-orient
的值是vertical
.
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-moz-box-orient:horizontal;
-webkit-box-orient:horizontal;
-moz-flex-direction:row;
-webkit-flex-direction:row;
-ms-flex-direction:row;
flex-direction:row;
}
- 以列倒序显示。
flex-dirction
的值是column-reverse
,box-orient
的值是vertical
但是需要配合box-direction:reverse
. (并未测试出box-orient的效果)
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-moz-box-orient:vertical;
-webkit-box-orient:vertical;
-moz-box-direction:reverse;
-webkit-box-direction:reverse;
-moz-flex-direction:column-reverse;
-webkit-flex-direction:column-reverse;
-ms-flex-direction:column-reverse;
flex-direction:column-reverse;
}
flex-flow
flex-flow
相当于flex-direction/flex-wrap
的合写。比如:
{
flex-flow:row wrap; //等同于下面两个写法
flex-wrap:wrap;
flex-dirction:row;
}
align-self
align-items
用在容器上表示所有子元素的情况。而align-self
用于子元素自身上,作用于自己的对齐情况。如果align-items
一样具有flex-start | flex-end | center | baseline | stretch
五个属性。
如:
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items:flex-start;
-webkit-align-items:flex-start;
-moz-align-items:flex-start;
-moz-box-align:start; /* 其实不起作用 */
-webkit-box-align:start; /* 其实不起作用 */
-ms-flex-align:start;
}
.left{
background: #ccc;
width: 100px;
-webkit-align-self:flex-end;
-moz-align-self:flex-end;
align-self:flex-end;
}
order
用于子元素的顺序,order
值小的在前面, 默认为0。兼容写法:
{
order:1;
-webkit-order:1;
}
例子:
.flex-container{
width: 700px;
height: 200px;
border:#999 solid 1px;
display:-webkit-box;
display:-moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
.left{
background: #ccc;
width: 100px;
order:2;
-webkit-order:2;
}
.mid{
background: #666;
width: 100px;
order:2;
-webkit-order:2;
}
.right{
margin: 5px 10px;
background: #333;
width: 100px;
}
上面例子看出,如果值相同则先出现的在前。
至此,关于flex
的东西都涉及到了,以后不会那么晕乎了。