Published on
1506

Flex布局使用过程中常见样式问题的处理方案

Authors
  • avatar
    Name
    小辉辉
    Twitter

前言

flex布局由于它的便利性,几行样式就能搞定前端前几年用浮动来实现布局的场景,可以说现在刚刚接触前端的人基本上都在用flex布局,在问到是否使用过浮动布局时,回答也都是否定的。

但是我们在使用flex布局的时候,一般都是很顺利的,但是又往往会遇到一些冷门的问题,对,这个人就是我,所以决定花了一点时间,记录下平时工作中遇到的几种特殊场景,方便后续持续跟踪学习。

布局异常

首先来说明下问题现象,这里以默认的水平布局举例,体现在设置父容器设置display: flex后,子元素分别有左右两部分,左边设置了固定宽度,右边想让它占满剩余宽度,如果两个子容器内部没有任何内容时,布局没有任何问题。

可是容器内是一段长文本时,主要是右侧容器,问题就来了,左侧容器的固定宽度失效了,也就是说右侧容器会占据了左侧容器一部分的宽度。

下面是基本布局结构代码:

<body>
  <div id="wrap">
    <div id="left">left content</div>
    <div id="right">
      <div id="right-wrap">
        大多数情况下,开发者需要将 flex 设置为以下值之一:
        auto,initial,none,或一个无单位正数。要查看这些值的效果,请尝试调整以下 flex 容器的大小:
      </div>
    </div>
  </div>
</body>
html,
body {
  height: 100%;
}
#wrap {
  display: flex;
  height: 100%;
}

#left {
  width: 200px;
  background-color: #333;
}

#right {
  flex-grow: 1;
  background-color: #777;
}
flex布局问题1

上面的示例中我们会发现,当右侧容器没有文本时,一切显示正常,但是我们加入了内容后,我们看到的效果是这样的,左侧的容器被压缩了。

flex-grow 设置 1 无效

flex布局问题2

由于左侧已经设置了固定宽度200px,那么为了达到右侧占满剩余宽度时,我们自然而然想到了flex-grow属性,该属性默认值为0,当其值是1时,如果父容器有剩余的宽度时会按比例占满,这也是一开始我们预期看到的效果。

但是为什么存在长文本时,容器会突然变大了呢?根本原因在于flex布局子容器的宽度计算是根据对于子容器内部宽度实际占用情况来决定的,

如果我们不对右侧容器设置宽度,默认值会是auto,也就是父容器占满可用的内容,于是我们就会看到右侧容器占有了多余的空间。

解决方案1,给左侧容器添加flex-shrink: 0属性,也就是告诉flex布局左侧容器不能被压缩。

解决方案2,给右侧容器添加width: 0属性。

解决方案3,右侧属性设置flex: 1属性

flex 设置 1 无效

flex布局问题1

但是当我们给右侧容器加上一个white-space: nowrap属性时,就会发现左侧容器又被压缩了,且父容器还出现了滚动条。

#right {
  flex: 1;
  white-space: nowrap;
  background-color: #777;
}

对于该问题,我们直接通过添加添加overflow: hidden样式来解决。

现象2,当我们在右侧容器内把长文本移动到一个单独的div元素时,奇怪的发现上述的flex: 1效果无效了,具体现象和上面一致,我们同样也能通过oveflow: hidden样式来解决,除此之外,设置width人员值或者是设置min-width: 0 能起到一样的效果。

flex-shrink 设置 0 无效

flex布局问题3

让我们回过头来,到第一个问题,假设我给左侧容器设置flex-shrink: 0,除此之外,右侧容器将长文本内容包裹在一个新的div容器下,且该容器同时设置white-space: nowrap和overflow: hidden样式,右侧去除flex-grow属性,按照flex-shrink的用法,此时左侧容器会收缩到最小宽度,且右侧没有滚动条。

<div id="right">
  <div>
    大多数情况下,开发者需要将 flex 设置为以下值之一:
    auto,initial,none,或一个无单位正数。要查看这些值的效果,请尝试调整以下 flex 容器的大小:
    大多数情况下,开发者需要将 flex 设置为以下值之一:
    auto,initial,none,或一个无单位正数。要查看这些值的效果,请尝试调整以下flex 容器的大小:
  </div>
</div>
html,
body {
  height: 100%;
}
#wrap {
  display: flex;
  height: 100%;
}

#left {
  width: 200px;
  flex-shrink: 0;
  background-color: #333;
}

#right {
  background-color: #777;
}

#right div {
  white-space: nowrap;
  overflow: hidden;
}

我们发现左右容器的宽度显示正常,但是在父容器却出现了滚动条。

这个问题的解决方案和上面两个问题相似,我们在右侧容器添加min-width: 0样式即可,这样父容器滚动条就会消失了。

设置 width 和 min-width 背后原理

可以这样理解,默认的值都是auto,如果内部值超出时,外部容器就会尽可能占据剩余空间,但是设置值以后,auto属性变失效了,于是变回到了正常的缩放情况。

要注意的是,min-width一般在子元素设置flex: 1时配合使用,这时候flex-basis值是具体值0%,而不是默认值auto,一般情况下推荐设置flex-shrink:0和具体设置另外一个容器width具体值来解决上述三类问题。

总结

css作为前端一个很重要的布局部分,我们在遇到问题的时候,必须得多做尝试,同时结合基础原理尽可能做到对每种现象能够分析个所以然出来,这样子才不会在下次遇到问题时还是模棱两可。

参考资料:

https://segmentfault.com/q/1010000043388498

https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing

https://www.bigbinary.com/blog/understanding-the-automatic-minimum-size-of-flex-items