flex 布局的浏览器兼容性方案

  • Post author:
  • Post category:其他




前言

flex 布局在目前前端开发中使用到的概率还是蛮大的,尽管它从诞生到现在已经经历了 N 年了,但是从个人的工作圈子来看,有很多人其实对 flex 布局的理解还是很表面,比如一味地使用 flex: 1 或者 flex: auto 等,导致一旦出现一些样式问题或者浏览器兼容问题,马上就无法处理了。

因此,个人从 flex 布局基础知识和浏览器兼容性两个方面,结合个人工作经验,整理了一篇文章,希望对大家有帮助,如有阐述有误之处,还望不吝指教!

文章大体分为两个部分,第一块是 flex 的基础知识,包括布局特性、属性特征等,相对偏理论些。第二块是 flex 的浏览器兼容问题总结,以及 flex 使用建议,这源于个人工作场景中实际碰到的问题,经尝试解决后的总结,偏实际应用一点。

如果对 flex 布局原理比较了解,但遇到浏览器兼容问题的同学来说,可以直接看第二块内容。



flex 布局 – 一维布局

flexbox 是一种一维的布局,因为一个 flexbox 一次只能处理一个维度上的元素布局,一行或者一列



flex 布局 – 容器属性



display: flex vs display: inline-flex



相同点

  • 对于容器内部的子元素而言,没有任何区别



差异

  • 对于容器本身而言,

    flex

    表现为 块级元素;

    inline-flex

    表现为 块级内联元素

    • 因此未给容器设置宽度时,

      flex

      容器默认宽度为100%(一行占满);

      inline-flex

      默认宽度会根据子元素的宽度去自适应

在这里插入图片描述



flex-direction



轴线 – 主轴 & 交叉轴

  • 主轴由

    flex-direction

    定义,可取

    row

    (横向主轴)、

    column

    (纵向主轴)等值。
  • 交叉轴则为与主轴垂直的轴线。

  • flexbox

    的特性是沿着主轴或者交叉轴对齐之中的元素。

在这里插入图片描述


在这里插入图片描述



起始线 & 终止线



起始线、终止线用于描述

flexbox

子元素的书写(排列)方向。

当主轴为 row(横向主轴)时:

  • 书写英文时,主轴起始线为左边;书写阿拉伯文时,主轴起始线为右边。
  • 交叉轴起始线是

    flexbox

    的顶部,终止线是底部,因为两种语言都是水平书写模式。

在这里插入图片描述


在这里插入图片描述


当主轴为 column(纵向主轴)时:

  • 主轴起始线为

    flexbox

    的顶部,终止线为

    flexbox

    的底部,因为两种语言都是水平书写模式。
  • 书写英文时,交叉轴起始线为左边;书写阿拉伯文时,交叉轴起始线为右边。



属性值与轴线、起始终止线的关系

假定以 row 为基准,那么取其他属性时的线位变化如下:

  • row-reverse:主轴 & 交叉轴不变;起始线 & 终止线 改变

    • 主轴的起始线、终止线互换;交叉轴的起始线、终止线不变
  • column:主轴 & 交叉轴互换;起始线 & 终止线 改变

    • 主轴的起始终止线,与交叉轴的起始终止线互换
  • column-reverse:主轴 & 交叉轴互换;起始线 & 终止线 改变

    • 主轴的起始终止线,与交叉轴的起始终止线互换
    • 交叉轴的起始线、终止线互换;主轴的起始线、终止线不变



justify-content



使子元素在主轴上对齐

  • 初始值是

    flex-start

    ,子元素从容器的起始线开始排列。

  • flex-end

    ,元素从容器终止线开始排列

  • center

    ,居中排列,每个元素紧邻

  • space-between

    ,占满容器,并且元素之间间隔相等

  • space-around

    ,占满容器,并且每个元素的左右空间相等

在这里插入图片描述



align-items



使子元素在交叉轴上对齐

  • 初始值是

    stretch

    • 未定义容器高度,容器会被拉伸到最高元素的高度;
    • 定义了容器高度,元素会被拉伸(收缩)到容器高度。

  • flex-start

    ,按容器的起始线对齐

  • flex-end

    ,按容器的终止线对齐

  • center

    ,居中对齐

在这里插入图片描述



align-content



使子元素在交叉轴方向对齐,但为多行对齐

  • 默认值是

    stretch

    ,剩余空间被所有行平分,以扩大它们的交叉轴尺寸

  • flex-start

    ,所有行从容器的起始线排列

  • flex-end

    ,所有行从容器终止线开始排列

  • center

    ,所有行在容器中间,紧凑排列

  • space-between

    ,所有行占满容器,并且每行之间间隔相等

  • space-around

    ,所有行占满容器,并且每行的上下空间相等

在这里插入图片描述



flex-wrap



换行方式

  • 默认 nowrap,不换行
  • wrap,换行
  • wrap-reverse,换行反向排列

在这里插入图片描述



flex-flow



flex-direction



flex-wrap

的合并写法



flex 布局 – 子元素属性



子元素默认样式

  • flex-direction: row,元素排列为一行,并从主轴的起始线开始
  • flex: 0 1 auto,元素不会在主轴方向拉伸,但会随可用空间会缩小
  • flex-wrap: nowrap,如果有太多元素超出容器,它们会溢出而不会换行
  • 如果一些元素比其他元素高,那么元素会沿交叉轴被拉伸来填满它的大小

在这里插入图片描述



flex-basis



元素的初始(基准)空间大小

  • 默认值是

    auto

    • 元素设置了宽度,

      flex-basis

      为设置的宽度
    • 元素未设置宽度,

      flex-basis

      为元素内容的尺寸

  • flex-basis

    属性优先于

    width

    属性;
  • 设为 0 ,则子元素的大小不在空间分配计算的考虑之内



flex-grow



元素沿主轴方向的扩张尺寸,会占据主轴上的可用空间

  • 按比例分配空间(默认为 0 ),扩张值为

    flex-basis

    基准乘以

    flex-grow

    扩张比例

    • 设置一样的值,则平分可用空间
    • 设置不同的值,按比例平分可用空间

下图为不同

flex-basis

的情况下,

flex-grow

均设为 1 的场景:

在这里插入图片描述



flex-shrink



元素沿主轴方向的收缩尺寸,只有在子元素总和超出主轴才会生效

  • 按比例分配空间(默认为 1 ),收缩值为

    flex-basis

    基准乘以

    flex-shrink

    收缩比例
  • 随着盒子越来越小,小的子元素最终会以

    min-content

    的大小进行铺设,后续空间会一直从大的子元素中移除

    • 所谓

      min-content

      ,即当前容器内部最小的不可断行元素的宽度

      • 下图 largeSizeContentWithoutWrap 是连续不可断行的,所以无法再压缩空间
      • 下图 middle-size-content-width-split-code 可以以横杠 – 断行,所以可以换行以压缩空间
      • 下图 content-content-content-content-content-content 已经被断行到不可再断行的宽度,因此无法再继续换行来压缩空间

下图为不同

flex-basis

的情况下,

flex-shrink

均设为 1 的场景:

在这里插入图片描述



order



项目的排列顺序

  • 数值越小,排列越靠前,默认为 0



align-self



允许单个项目有与其他项目不一样的对齐方式

  • 可覆盖

    align-items

    属性,默认值为

    auto
  • 表示继承父元素的

    align-items

    属性

    • 如果没有父元素,则等同于

      stretch



几个 flex 样式的简写



flex: initial

相当于 flex: 0 1 auto



flex: auto

相当于 flex: 1 1 auto



flex: none

相当于 flex: 0 0 auto



flex: 1

相当于 flex: 1 1 0



flex: auto 与 flex: 1 的区别



flex: 1 1 auto

  • 在各元素初始宽度基础上,平均分配可用空间
  • 各元素宽度不相等,初始宽度大的分配后宽度也大



flex: 1 1 0

  • 在各元素 0 宽度的基础上,平均分配可用空间
  • 各元素宽度相等

在这里插入图片描述



flex 布局 – 浏览器兼容性



浏览器兼容性概览

  • 红色部分为不支持 flex 规范
  • 黄色部分为只支持老的 09 版 flex 规范(display: box; )
  • 绿色部分为完全支持新的 12 版 flex 规范(display: flex; )

在这里插入图片描述



flex 规范,09 版 vs 12 版

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述



支持少数低版本浏览器的方案

  • 联合使用支持 09 版和 12 版的 flex 布局
.container {
	display: box; 
	display: flex; 
}



注意
  • 浏览器兼容语法(-webkit- 等)可以通过postcss 等工具实现
  • 但 09 版 flex 不支持很多特性



chrome 49 的兼容性问题



问题描述

父元素

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%;



chrome 79 以上的兼容性问题



问题描述

当父元素设置

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)



chrome 49 与 chrome 79 以上的另一个差异点



差异描述

  • flexbox 一个子元素设置了 flex,另一个子元素设置了很高的高度
  • 当 flexbox 高度不足以容纳两者时,两者高度都会受到压缩
  • 但在 chrome49 下设置了 flex 的子元素,会被压缩到连其子元素都无法完整展示
  • 而 chrome79 下设置了 flex 的子元素,则会尽可能保留其子元素的展示

chrome 49

在这里插入图片描述

chrome 79 以上

在这里插入图片描述



解决方案

若要保持设置了 flex 的子元素的完整展示,最好设置 flex 的同时设置 flex-shrink: 0;



flex 布局使用建议



针对横向布局

按照一般写法即可

.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


重申几点:

  • 上面 flex 布局的基础知识是基于自己看过的很多文档归纳的,可能有些描述摘录了其他地方的文章的用词或片段,如有侵权请告知,我会删掉。

    • 因为整理的时候查的资料比较多,现在很多地方已经想不起来参考了哪里的文章,所以不大好去附加参考资料,请见谅。
  • 后面 flex 布局的兼容性问题,更多的是基于工作场景遇到并解决后整理的。当然也有查各方面资料(虽说目前网上这块的资料不够详尽),但是也有个人经验的总结在里面。

    • 因此后面如果个人再遇到其他 flex 的浏览器兼容性问题,还会再总结补充进来。
  • 虽说这篇文章不能算是完全原创,但是毕竟也是个人花了时间和精力整理、基于实际工作场景尝试和总结的,因此如需转载,还请附上此出处哈!

    • 也算是对个人总结的一些认可吧 -.-



版权声明:本文为qq_32875037原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。