flex 布局在目前前端开发中使用到的概率还是蛮大的,尽管它从诞生到现在已经经历了 N 年了,但是从个人的工作圈子来看,有很多人其实对 flex 布局的理解还是很表面,比如一味地使用 flex: 1 或者 flex: auto 等,导致一旦出现一些样式问题或者浏览器兼容问题,马上就无法处理了。
因此,个人从 flex 布局基础知识和浏览器兼容性两个方面,结合个人工作经验,整理了一篇文章,希望对大家有帮助,如有阐述有误之处,还望不吝指教!
文章大体分为两个部分,第一块是 flex 的基础知识,包括布局特性、属性特征等,相对偏理论些。第二块是 flex 的浏览器兼容问题总结,以及 flex 使用建议,这源于个人工作场景中实际碰到的问题,经尝试解决后的总结,偏实际应用一点。
如果对 flex 布局原理比较了解,但遇到浏览器兼容问题的同学来说,可以直接看第二块内容。
flexbox 是一种一维的布局,因为一个 flexbox 一次只能处理一个维度上的元素布局,一行或者一列
flex
表现为 块级元素;inline-flex
表现为 块级内联元素
flex
容器默认宽度为100%(一行占满);inline-flex
默认宽度会根据子元素的宽度去自适应flex-direction
定义,可取 row
(横向主轴)、column
(纵向主轴)等值。flexbox
的特性是沿着主轴或者交叉轴对齐之中的元素。flexbox
子元素的书写(排列)方向。当主轴为 row(横向主轴)时:
flexbox
的顶部,终止线是底部,因为两种语言都是水平书写模式。
当主轴为 column(纵向主轴)时:
flexbox
的顶部,终止线为 flexbox
的底部,因为两种语言都是水平书写模式。假定以 row 为基准,那么取其他属性时的线位变化如下:
flex-start
,子元素从容器的起始线开始排列。flex-end
,元素从容器终止线开始排列center
,居中排列,每个元素紧邻space-between
,占满容器,并且元素之间间隔相等space-around
,占满容器,并且每个元素的左右空间相等stretch
flex-start
,按容器的起始线对齐flex-end
,按容器的终止线对齐center
,居中对齐stretch
,剩余空间被所有行平分,以扩大它们的交叉轴尺寸flex-start
,所有行从容器的起始线排列flex-end
,所有行从容器终止线开始排列center
,所有行在容器中间,紧凑排列space-between
,所有行占满容器,并且每行之间间隔相等space-around
,所有行占满容器,并且每行的上下空间相等为 flex-direction
和 flex-wrap
的合并写法
auto
flex-basis
为设置的宽度flex-basis
为元素内容的尺寸flex-basis
属性优先于 width
属性;flex-basis
基准乘以 flex-grow
扩张比例
下图为不同 flex-basis
的情况下,flex-grow
均设为 1 的场景:
flex-basis
基准乘以 flex-shrink
收缩比例min-content
的大小进行铺设,后续空间会一直从大的子元素中移除
min-content
,即当前容器内部最小的不可断行元素的宽度
下图为不同 flex-basis
的情况下,flex-shrink
均设为 1 的场景:
align-items
属性,默认值为 auto
align-items
属性
stretch
相当于 flex: 0 1 auto
相当于 flex: 1 1 auto
相当于 flex: 0 0 auto
相当于 flex: 1 1 0
.container {
display: box;
display: flex;
}
父元素 flex: 1
,子元素 height: 100%
,因内容较少无法填充满父元素
父元素未设置 height
,故子元素获取不到父元素的 height
通过父元素 absolute
,子元素 relative
,这样子元素的高度就会根据父元素的高度进行计算
规范中有提到,如果包含块的高度没有显式地指定(高度由内容决定),并且不是绝对定位元素,则计算值为 auto,高度和百分比值是没办法进行计算的! auto * 100/100 = NaN
子元素 absolute
带来的影响,比如需要再设置 width: 100%
子元素不使用 height: 100%
,而使用 flex-grow
来占满空间
父元素不使用 flex: 1
,而使用 display: flex;
+ height: 100%;
应用于 display: flex
的元素,使其成为 flex 容器。
这会自动设置 align-items: stretch
,会告诉 child(.item)扩展父级的完整高度。
Chrome49
浏览器针对子元素设置 height: 100%
后因内容较少无法填充满父元素的情况,
建议父元素使用 display: flex;
+ height: 100%;
当父元素设置 flex: 1
填充满容器,子元素设置 height: 100%
后,子元素内容过多会超出父元素
对于一个设置了 flex: 1
的元素,再对其设置 min-height:0
,保证内容不超出外层容器
父元素设置 min-height: 0
相当于告诉子元素父元素 height > 0
,子元素可以由此间接地拿到父元素的高度,然后设置 height: 100%
保持父元素同样的高度,避免溢出
要兼容 chrome49
的话还需使用 display: flex;
+ height: 100%;
替换 flex: 1
Chrome79
以上浏览器,针对子元素设置 height: 100%
因内容过多超出父元素的情况,建议父元素使用 min-height: 0;
(Chrome 79) + display: flex;
+ height: 100%;
(Chrome 49)
若要保持设置了 flex 的子元素的完整展示,最好设置 flex 的同时设置 flex-shrink: 0;
按照一般写法即可
.container {
display: flex;
flex-direction: row;
}
需要增加兼容 chrome49 以及 chrome79 以上的样式
.container {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
视情况灵活使用 flex-basis
、flex-grow
、flex-shrink
的组合,而不是一味地全部使用 flex:1
或者 flex: auto
附上案例项目的 git 地址:(案例可能写的不是很好-0-)
https://github.com/hezhikai/blog-flex_compatible.git
重申几点: