年前做年报活动的时候,遇到了
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的东西都涉及到了,以后不会那么晕乎了。