如何避免在 Firefox 中用滚动条包裹长列表中的元素

How to avoid wrapping of elements in a long list with scrollbars in Firefox

我有一个很长的 flex 列表,它应该在项目(按钮)不够用时包装它 space(flex-wrap)。但是,一旦列表获得滚动条,即使有足够的 space.

,项目也会在 Firefox 中被包裹起来

Chrome 按预期并排显示按钮。

(我在这里使用 Vue,以保持 HTML 简单。它实际上只创建了 text/button 元素 30 次)

new Vue({
  el: "#app",
})
body, html {
  margin: 0;
}

.container {
  position: absolute; 
  height: 100vh; 
  overflow: auto;
}

.row {
  display: flex;
  flex-wrap: wrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div class="container" id="app">
  <div v-for="(i, index) in 30" :index="i">
    Text
    <div class="row">
      <button>Button 1</button>
      <button>Button 2</button>
    </div>
    <hr />
  </div>
</div>

我看到 flex 容器按照 height: 100vh; 的预期在视口中占用了整个可用的 space。我正在使用火狐浏览器。

那么你的下一个问题不是垂直 space 而是如何正确显示内联元素。您的按钮应该以 display: inline-block; 开头。

那么你应该尝试设置最近的父元素的宽度...我首先在父元素 .container > div 中添加了一条规则,以便将它们的宽度设置为 width:fit-content;。后来我将其移至 .container,并使用 overflow-y: scroll.

更好地调整了滚动条功能的大小

当使用 overflow: auto 时,它只会在需要时显示滚动条,但容器大小不会考虑是否显示滚动条的可能性。因此,如果它们被显示,它们将占据内部 space 覆盖内容。

当使用 overflow: scroll 时,它将始终显示滚动条,并且容器大小将始终考虑到它们。

为了在使用 overflow: auto 时也使容器大小自适应,这里使用了几个选项,例如:

scrollbar-gutter: stable;

https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-gutter

但最后,为了更好地控制容器的宽度,您可以通过 javascript 检查内容是否溢出容器,只有在这种情况下才添加(或取消设置相反的情况)css 属性 overflow: scroll.

我还添加了 box-sizing: border-box 以避免容器占用一些额外的垂直空间 space。

这里的演示展示了两个并排的“应用程序”,一个的容器内容未溢出(因此没有滚动条),另一个容器内容溢出(因此显示滚动条):

如果 window 调整了大小,此解决方案会刷新容器;如果内容的溢出情况发生变化,adds/remove 会刷新滚动条。

new Vue({
  el: "#app1", 
})

new Vue({
  el: "#app2", 
})

refreshPage();
window.addEventListener('resize', refreshPage);

function refreshPage(){
  const app1 = document.getElementById('app1');
  const app2 = document.getElementById('app2');

  const isApp1Overflowing = app1.scrollHeight > app1.clientHeight;
  const isApp2Overflowing = app2.scrollHeight > app2.clientHeight;
  
  if (isApp1Overflowing)
    app1.style.overflowY = 'scroll';
  else
    app1.style.overflowY = 'unset';

  if (isApp2Overflowing)
    app2.style.overflowY = 'scroll';
  else
    app2.style.overflowY = 'unset';
}
body, html {
  margin: 0;
}

.container {
  /*added borders to container to better highlights its size*/
  border: solid 1px black;  
  /*it will take 100% of viewport height*/
  height: 100vh;   
  /*scroll instead of auto to have the scrollbar not occupying inner space*/
  /*overflow-y: auto;*/
  /*scrollbar-gutter: stable;*/
  /*fit-content will adapt to content, otherwise if unset will go 100%*/
  width: fit-content;
  /*to add some padding from the container borders*/
  padding: 5px;  
  white-space: nowrap;
  vertical-align:top;
  box-sizing: border-box;
}

.row button{
  /*to have the buttons next to each other*/
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div class="container" id="app1" style="display: inline-block">
  <div v-for="(i, index) in 5" :index="i">
    Text
    <div class="row">
      <button>Button 1</button>
      <button>Button 2</button>
    </div>
    <hr />
  </div>
</div>

<div class="container" id="app2" style="display: inline-block">
  <div v-for="(i, index) in 25" :index="i">
    Text
    <div class="row">
      <button>Button 1</button>
      <button>Button 2</button>
    </div>
    <hr />
  </div>
</div>