Flexbox 浏览器兼容小结

Posted by Damon on 2016-08-08

浏览器兼容性问题,是前端工程师的一个必然要遇到的事情。今天我们来聊聊flexbox 的兼容问题,PC端大家都看到了http://caniuse.com/#search=flex 除了IE支持都很好,但到了移动端就惨不忍睹了(特别是国产手机)。其主要原因还是国产浏览器厂商的更新和支持更不上国际速度,还拿着09年的标准来糊弄自然会有问题。很多人不敢用flexbox说它在国产手机里支持不好云云,其实主要原因还是,我们对其在定制过程中的各个版本规范搞不清状况。好了我们来看看吧:

注:对于IE,我们兼容到10

历史

09年到现在flexbox分别经历了三种方式:display:box;display:flexbox 还有现在的display:flex;

If you Google around about Flexbox, you will find lots of outdated information. Here’s how you can quickly tell:

  • If you are looking at a blog post (or whatever) about Flexbox and you see display: box; or a property that is box-{*}, you are looking at the old 2009 version of Flexbox.
  • If you are looking at a blog post (or whatever) about Flexbox and you see display: flexbox; or the flex() function, you are looking at an awkward tweener phase in 2011.
  • If you are looking at a blog post (or whatever) about Flexbox and you see display: flex; and flex-{*} properties, you are looking at the current (as of this writing) specification.

flexbox最初定义的时候其实2009年定义了第一个版本以后,就有浏览器厂商率先实现了display:box的功能。到了2011年大家对原来实现的功能还不满意,为了不改变原来对display:box的支持,就有了display:flexbox;。到后来规范逐渐成熟再加上功能需要在加完善,所以就到了display:flex,还会不会改鬼知道呢。

支持情况

我们从caniuse上看一下支持度。

大体总结了一下,除了Opera mobile12,还有IE,各大浏览器都是支持flexbox的旧版语法的。

注:最新的语法才加入了wrap的属性,所以旧版肯定是不支持的

解决方案

从上面的调研可以看出,其实最新的flex是兼容之前的语法的,只不过有一些新增的语法。那么解决这样的兼容问题显而易见的就是增加上旧版的语法,就可以解决一些支持旧版语法的浏览器啦。

第一篇我们说到,flexbox分为container和item,所以兼容的写法也分两部分。

container

1
2
3
4
5
6

.grid{
display: -webkit-box; /* Chrome 4+, Safari 3.1, iOS Safari 3.2+ */
display: -webkit-flex; /* Chrome 21+, Safari 6.1+, iOS Safari 7+, Opera 15/16 */
display: flex; /* Chrome 29+, Firefox 22+, IE 11+, Opera 12.1/17/18, Android 4.4+ */
}

item

1
2
3
4
5
6

.grid-cell{
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
}

看到这里,你可能就有疑问,这样每次写这么多前缀不累吗?我们有工具啊:
我们可以使用类似autoprefixer, 或者是sass\less等工具来写css。另外安利一个sass的mixin大家可以看看compass-flex

还有一种方式就是,完全用老版本的display:box来写,这样的话 除了一些新特性比如flex-wrap不能用以外(如果你觉得没必要用新特性)别的基本没什么问题,这里贴一份朋友写的grid系统 (据说兼容Android2.3):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
.row {
width: 100%;
margin: 0;
padding: 0;
box-sizing: border-box;
height: auto;
display: block;
zoom: 1;
}
.row.flex:after {
display: none;
}
.row.flex > .col-flex,
.row.flex > .col,
.row.flex > .col-1,
.row.flex > .col-2,
.row.flex > .col-3,
.row.flex > .col-4,
.row.flex > .col-5,
.row.flex > .col-6,
.row.flex > .col-7,
.row.flex > .col-8,
.row.flex > .col-9,
.row.flex > .col-10,
.row.flex > .col-11,
.row.flex > .col-12 {
float: none;
}
.row.flex > .col-flex {
-webkit-box-flex: 1;
}
.row:after {
content: " ";
visibility: hidden;
display: table;
height: 0;
clear: both;
}
.row > .col,
.row > .col-1,
.row > .col-2,
.row > .col-3,
.row > .col-4,
.row > .col-5,
.row > .col-6,
.row > .col-7,
.row > .col-8,
.row > .col-9,
.row > .col-10,
.row > .col-11,
.row > .col-12 {
-webkit-box-flex: 0;
padding-left: 0;
padding-right: 0;
display: block;
float: left;
}
.row > .col-1 {
width: 8.33333%;
}
.row > .col-offset-1 {
margin-left: 8.33333%;
}
.row > .col-2 {
width: 16.66667%;
}
.row > .col-offset-2 {
margin-left: 16.66667%;
}
.row > .col-3 {
width: 25%;
}
.row > .col-offset-3 {
margin-left: 25%;
}
.row > .col-4 {
width: 33.33333%;
}
.row > .col-offset-4 {
margin-left: 33.33333%;
}
.row > .col-5 {
width: 41.66667%;
}
.row > .col-offset-5 {
margin-left: 41.66667%;
}
.row > .col-6 {
width: 50%;
}
.row > .col-offset-6 {
margin-left: 50%;
}
.row > .col-7 {
width: 58.33333%;
}
.row > .col-offset-7 {
margin-left: 58.33333%;
}
.row > .col-8 {
width: 66.66667%;
}
.row > .col-offset-8 {
margin-left: 66.66667%;
}
.row > .col-9 {
width: 75%;
}
.row > .col-offset-9 {
margin-left: 75%;
}
.row > .col-10 {
width: 83.33333%;
}
.row > .col-offset-10 {
margin-left: 83.33333%;
}
.row > .col-11 {
width: 91.66667%;
}
.row > .col-offset-11 {
margin-left: 91.66667%;
}
.row > .col-12 {
width: 100%;
}
.row > .col-offset-12 {
margin-left: 100%;
}
.flex {
display: -webkit-box;
display: box;
-webkit-box-orient: horizontal;
box-orient: horizontal;
}
.flex.vertical {
-webkit-box-orient: vertical;
box-orient: vertical;
}
.flex.start {
-webkit-box-pack: start;
}
.flex.center {
-webkit-box-pack: center;
}
.flex.end {
-webkit-box-pack: end;
}
.flex.justify {
-webkit-box-pack: justify;
}
.flex.top {
-webkit-box-align: start;
}
.flex.middle {
-webkit-box-align: center;
}
.flex.bottom {
-webkit-box-align: end;
}

其他的不兼容特性

  • 在旧版的规范中,使用比例伸缩布局时,子元素的内容长短不同会导致无法“等分”,这个时候,我们需要给子元素设置一个“width:0%”来解决问题
  • 不要给item设置“margin:auto”的属性,在部分安卓机下,它会导致该元素的宽度撑开到100%占位
  • 旧版的box item要求属性是块级结构,所以很多inline元素需要设置display:block等才能显示正常
  • text-overflow: ellipsis;在display:flex元素上无效

记住上面的坑,避免跳进去。

方法论

其实兼容性的解决办法是有一套方法论的。我个人觉得做到以下几点是必要的:

  • 确定业务需求面向的运行环境是怎样的,需要兼容哪些浏览器;
  • 查改特性的兼容性,兼容到了哪个版本,该不该用这个属性,或者给出兼容的写法;
  • 学会使用工具;
  • 充分测试,把兼容问题当做一种自我积累和提升积极面对,不断完善。

好了就这么多,上面的坑的列表大家可以补充,欢迎关注我的专栏知乎前端杂货铺

参考资料