移动端开发小记 - Flexbox
作者: 发布于:

在开发移动端页面的时候,出去布局方便和减少代码量的考虑,使用了 Flexbox 的布局方式,在其中也遇到了一些问题,简单记录下。

什么是 Flexbox

说到 Flexbox,大家应该都不陌生,网络上也有 N 多的教程。但是在这里还是简单说一下,就当回顾知识了吧。

CSS 2.1 定义了四种布局模式 ― 由一个盒与其兄弟、祖先盒的关系决定其尺寸与位置的算法:

  • 块布局 ― 为了呈现文档而设计出来的布局模式;
  • 行内布局 ― 为了呈现文本而设计出来的布局模式;
  • 表格布局 ― 为了用格子呈现 2D 数据而设计出来的布局模式;
  • 定位布局 ― 为了非常直接地定位元素而设计出来的布局模式,定位元素基本与其他元素毫无关。

而 Flexbox(伸缩布局)是为了呈现复杂的应用与页面而设计出来的,一种更加方便有效,能够在未知或者动态尺寸的情况下自由分配容器空间的布局方式。

要说明 Flexbox 的布局模型,就必须要放规范上的这张图:

  • main axis(主轴)
  • main dimension(主轴方向)
  • The main axis of a flex container is the primary axis along which flex items are laid out. It extends in the main dimension.
  • 主轴是伸缩项目在伸缩容器里分布所遵循的主要轴线,在主轴方向上延伸。
  • main-start(主轴起点)
  • main-end(主轴终点)
  • The flex items are placed within the container starting on the main-start side and going toward the main-end side.
  • 伸缩项目从容器的主轴起点开始放置,直到主轴终点。
  • main size(主轴尺寸)
  • main size property(主轴尺寸属性)
  • A flex item’s width or height, whichever is in the main dimension, is the item’s main size. The flex item’s main size property is either the width or height property, whichever is in the main dimension.
  • 伸缩项目在主轴方向上的长或者宽是这个项目的主轴尺寸。一个伸缩项目的主轴属性是在主轴方向上的长或者宽属性。
  • cross axis(侧轴)
  • cross dimension(侧轴方向)
  • The axis perpendicular to the main axis is called the cross axis. It extends in the cross dimension.
  • 和主轴垂直的轴叫做侧轴,它在侧轴方向上延伸。
  • cross-start(侧轴起点)
  • cross-end(侧轴终点)
  • Flex lines are filled with items and placed into the container starting on the cross-start side of the flex container and going toward the cross-end side.
  • 包含伸缩元素的伸缩行从容器的侧轴起点开始放置,直到侧轴终点。
  • cross size(侧轴尺寸)
  • cross size property(侧轴尺寸属性)
  • The width or height of a flex item, whichever is in the cross dimension, is the item’s cross size. The cross size property is whichever of width or height that is in the cross dimension.
  • 伸缩项目在侧轴方向上的长或者宽是它的侧轴尺寸。侧轴尺寸属性则是在侧轴方向上的长或者宽属性。

使用 Flexbox

现在大部分的主流浏览器都已经支持了 Flexbox 或者它的旧版语法。如果是使用在移动端,基本上是都支持的。为了兼容新老版本的语法,可以这样使用( Less ):

//父元素
.flex-box() {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}
//子元素
.flex(@v) {
  -webkit-box-flex: @v;
  -moz-box-flex:  @v;
  -webkit-flex:  @v;
  -ms-flex:  @v;
  flex:  @v;
}

为子元素设置了 flex: 1,这样容器里面的子元素可以均分容器的空间。当然,可以为某个子元素指定一个宽度,这样剩下的子元素就会平分剩下的空间。

如下图中的品牌墙:

flex-basis

这个属性,还是要稍微说一说的。这个属性是新版规范里面提到的属性。它用来描述伸缩元素( flex-item )的初始主轴尺寸和基准值,也就是在根据伸缩比率计算剩余空间分布之前的尺寸值,如果在 flex 中省略了这个值,则默认值是 0注意没有单位 。它的另一个取值是 auto ,这个时候,元素的初始主轴长度和基准值就是它本身的主轴长度,即取决于本身的内容长度。

两个取值的区别如下图:

看图更容易理解一些:值为 0 时,元素分配的是容器的空间。而当值为 auto 时,它分配的是减去元素内容之后剩余的容器空间。

在值为 auto 时,它的表现跟老版 Flex 规范的伸缩比例表现是一致的,如果盒子内容大小不一致,则每个盒子最后分配的空间大小也不一致。

所以,在处理这个显示异常时,要在元素上加一个 width: 0%; 来使其表现的正常。实际上,flex-basis: 0; 的行为就是为元素加上一个类似 width: 0%; 的属性,来分配容器空间。

Flexbox 这个模块有很多的属性,这里只介绍最基本的使用,更多内容详见规范或者 Google。

需要注意的点

  • 低版本安卓下大多用的是老版本的规范,所以会导致一些问题:
  • 在使用比例伸缩时会因为盒子内容大小不等导致内容无法等分的问题,这个时候可以为这个元素添加 width: 0%; 将其原始大小设为 0(比如 UC 浏览器,魅族 MX4,三星 N7100);
  • 旧版要求伸缩元素( flex-item )必须是块级元素,所以 inline 元素需要设置 display: block; 才可以正常显示。有部分国产手机的浏览器上就是这样的(比如:Vivo X3SW);
  • Flex item 里面如果有一个块元素,设置了 margin-top,会出现溢出的问题,表现就是 margin 无效。需要在这个元素上添加 overflow:hidden; 来使其正常显示。
  • 因为 Flexbox 有新版和旧版规范,新版的有些属性(比如:flex-wrap),老版规范下并不支持,出于兼容性,最好避免使用;
  • text-overflow: ellipsis;display: flex; 元素上是没有效果的。

By the way

还有一个有用的 CSS 属性,在移动端已经基本支持了,就是 box-sizing: border-box;。它在使用 padding 时非常有用,可以避免 widthpadding 的计算。可以这样子用:

.box-sizing(@v) {
  -webkit-box-sizing: @v;
  -moz-box-sizing: @v;
  box-sizing: @v;
}

不过,要注意,在这种盒模型下,边框的宽度也会算在宽度里。