解决Flexbox item/弹性盒子项目无法正确shrink/收缩,导致父容器溢出

问题描述

可滚动容器

现在需要实现这样一个布局:
布局
上面若干个固定高度的内容,最下面是一个可滚动的列表,滚动列表占据剩下的所有空间。最外层容器高度占据整个浏览器窗口高度的 100%,且最外层容器不可滚动。

这个实现思路比较明显,只需要用 Flex 布局,只允许最下面一个容器增长即可。

<div id="full">
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
    <div id="scrollable">
      <div>BBBBB</div>
      <div>BBBBB</div>
      <div>BBBBB</div>
      <div>BBBBB</div>
      <div>BBBBB</div>
      ...
    </div>
  </div>
</div>
html, #full, body {
  padding: 0;
  margin: 0;
  height: 100%;
}

#full {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#full * {
  flex: 0 1 auto;
}

#scrollable {
  flex: 1 1 auto;
  overflow-y: auto;
}

Demo。效果图:
在这里插入图片描述

再嵌套一层

现在需求变了,需要在这个列表上面加一个标题,然后再在外面套一个边框,以突出显示。

这个也简单,只需要再嵌套一个 div 即可。

<div id="full">
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div class="fixed-item">AAAA</div>
  <div id="scrollable-item">
    <p>[Scrollable Title]</p>
    <div id="scrollable">
      <div>BBBBB</div>
      <div>BBBBB</div>
      <div>BBBBB</div>
      ...
    </div>
  </div>
</div>
html, #full, body {
  padding: 0;
  margin: 0;
  height: 100%;
}

#full {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#full * {
  flex: 0 1 auto;
}

#scrollable-item {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  
  padding: 10px;
  margin: 10px;
  border: 1px solid black;
}

#scrollable {
  overflow-y: auto;
}

Demo。但是你很快就会发现新的问题:
在这里插入图片描述
列表居然不滚动了,反而是页面变成滚动的了!

问题原因&解决

如果你打开 DevTools 的 Flex 调试画面,如图:
在这里插入图片描述
可以看见 scrollable-item 的下半部分被阴影覆盖。阴影的意思是,在这个 Flex 布局中,这一部分是空隙,或者说空白部分。
也就是说我们的 Flex 布局并没有问题,Flex 布局有尝试收缩 scrollable-item,但是失败了,scrollable-item 溢出了而已。

为什么会溢出?

Flex 对其子项的收缩要受到 min-heightmin-width 的限制。根据 MDN 对 min-width 的解释min-width 的默认值为 auto。这个 auto 有很多含义。其中,如果当前元素是 Flex 子项:

  1. 如果当前元素有显式设置宽度(例如 width 的值),那么 min-width 就是显示设置的宽度
  2. 否则,值和 min-content 相同,也就是元素内容的最小宽度.

我们这里是高度,min-heightmin-width 一样,默认值是元素内容的最小高度。scrollable-item 元素的内容就是一个标题 + 一个列表,因此最小高度就是“一个标题 + 一个列表”的高度

最小高度就是内容高度,那当然没法收缩了。解决方法也很简单,设置 min-height: 0 即可

#scrollable-item {
  /* ... */
  min-height: 0;
}

Demo。效果图:
在这里插入图片描述

为什么第一个例子里没有这个问题呢?

因为如果当前元素是 Flex 子项的同时还可滚动的话,那么 min-width 默认为 0。例一中的列表恰好满足这个条件,而例二中由于在外面又套了一层 div,滚动的实际是 Flex 子项的子元素,不满足这个条件。因此例二要手动设置 min-height 而例一不需要。

参考

https://stackoverflow.com/questions/36230944/prevent-flex-items-from-overflowing-a-container
https://developer.mozilla.org/en-US/docs/Web/CSS/min-width#browser_compatibility

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值