如何防止flex容器溢出/下溢

How can I prevent a flex container from overflowing/underflowing?

本文关键字:溢出 下溢 何防止 flex      更新时间:2023-09-26

我有一个flexbox容器,可以通过拖动来调整大小。如何防止容器溢出(变得太小并开始隐藏某些项目)或下溢(变得太大并显示空白)?

在下面的示例中,当所有项目都达到18px高度时(最后一个除外),容器应停止收缩,而当所有项目达到其最大高度时(不应出现空格),容器则应停止膨胀。

const resizable = document.querySelector('.flex');
let startHeight = NaN;
let startY = NaN;
resizable.addEventListener('mousedown', e => {
  startHeight = resizable.getBoundingClientRect().height;
  startY = e.pageY;
});
window.addEventListener('mousemove', e => {
  if (isNaN(startY) || isNaN(startHeight)) {
    return;
  }
  
  resizable.style.height = (startHeight + e.pageY - startY) + 'px';
});
window.addEventListener('mouseup', () => {
  startHeight = startY = NaN;
});
.flex {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid black;
  cursor: ns-resize;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.item-1 {
  background: red;
  height: 40px;
  max-height: 60px;
  flex: 1;
}
.item-2 {
  background: blue;
  flex: none;
}
.item-3 {
  background: green;
  height: 50px;
  max-height: 50px;
  flex: 1;
}
.item-4 {
  background: yellow;
  height: 30px;
  flex: none;
}
<div class="flex">
  <div class="item-1">
    Item 1
  </div>
  <div class="item-2">
    Item 2
  </div>
  <div class="item-3">
    Item 3
  </div>
  <div class="item-4">
    Item 4
  </div>
</div>

最好使用纯CSS解决方案。该解决方案应该允许缩小容器,使所有物品都处于最小尺寸,并将其扩展,使所有项目都占据最大尺寸在容器的CSS中硬编码最小和最大高度是不可接受的我正在寻求一个通用的解决方案。

我认为纯CSS解决方案在这里是不可能的,因为您完全使用JavaScript设置高度。

你可以像我在下面的片段中那样添加一个保护。当可调整大小的大小为零时,以及当它很大时,您也可以计算底部高度,并在此基础上引入边界(可能性能更好,但dom变化不好)

const resizable = document.querySelector('.flex');
const lastChild = resizable.querySelector(':last-child');
const resizableBorderBottom = 1;  // hardcoded - could be computed too
let startHeight = NaN;
let startY = NaN;
resizable.addEventListener('mousedown', e => {
  /* 
   * here we assume that the bottom of the last child
   * is the same as the bottom of the resizable for simplicity
   */
  startHeight = resizable.getBoundingClientRect().height;
  startY = e.pageY;
});
window.addEventListener('mousemove', e => {
  if (isNaN(startY) || isNaN(startHeight)) {
    return;
  }
  const lastHeight = resizable.style.height;
  resizable.style.height = ((startHeight + e.pageY - startY) | 0) + 'px';
  const lastChildBottom = lastChild.getBoundingClientRect().bottom | 0;
  const resizableBottom = (resizable.getBoundingClientRect().bottom | 0) - resizableBorderBottom;
  // check if we need to revert the change
  if (lastChildBottom !== resizableBottom) {
    resizable.style.height = lastHeight;
  }
});
window.addEventListener('mouseup', () => {
  startHeight = startY = NaN;
});
.flex {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid black;
  cursor: ns-resize;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.item-1 {
  background: red;
  height: 40px;
  max-height: 60px;
  flex: 1;
}
.item-2 {
  background: blue;
  flex: none;
}
.item-3 {
  background: green;
  height: 50px;
  max-height: 50px;
  flex: 1;
}
.item-4 {
  background: yellow;
  height: 30px;
  flex: none;
}
<div class="flex">
  <div class="item-1">
    Item 1
  </div>
  <div class="item-2">
    Item 2
  </div>
  <div class="item-3">
    Item 3
  </div>
  <div class="item-4">
    Item 4
  </div>
</div>