防止弹性项目超过父高度并使滚动条工作

Posted

技术标签:

【中文标题】防止弹性项目超过父高度并使滚动条工作【英文标题】:Prevent flex item from exceeding parent height and make scroll bar work 【发布时间】:2019-02-28 11:04:57 【问题描述】:

如何防止带有滚动条的子 div 和 flex:1 在 Firefox 中超过其父 flexbox 的高度?它在 Chrome 中可以正常工作。

CodePen 链接(如果您更喜欢 Stack Overflow sn-ps): https://codepen.io/garyapps/pen/ZMNVJg

详情

我有一个固定高度的弹性容器。它有一个flex-direction:column 设置,它包含多个垂直堆叠的子div。其中一个子 div 具有 flex:1 属性,而其他子 div 具有固定高度。

我的期望是具有flex:1 属性的子 div 将扩展以填充剩余的垂直空间。这按预期工作。

我还给了子 div 一个overflow-y:scroll 属性,这样如果其中的内容超过它的高度,就会出现滚动条。这在 Chrome 中运行良好。然而,在 Firefox 中,这个孩子的身高增加了,超过了它的父 div。

在 Chrome 中:

在 Firefox 中:

正如您在屏幕截图中看到的那样,我有两次出现此问题,一次在左侧面板中,另一次在右侧面板中。在 Chrome 中,子 div 的高度保持不变,出现滚动条,并且不会超出父 div 的高度。在 Firefox 中不会出现滚动条,并且子 div 的高度会增加并超过其父级。

我查看了其他一些关于 SO 的类似问题,并且在许多情况下设置 min-height:0 属性解决了 Firefox 中的问题。但是,我尝试将min-height:0 添加到父母、孩子、父母和孩子,但没有运气。

请在 Chrome 和 Firefox 中运行下面的代码 sn-p 来查看两种浏览器的区别。

如果有任何关于如何防止子 div 增长的建议,我将不胜感激。

(注意使用的是Bootstrap 4,代码sn-p引用了bootstrap 4的.css文件CDN)

代码片段

.body-content 
        height: 300px;   
        max-height:100%;
        border: 3px dashed purple;
        display:flex;                       
        flex-direction: column;             
    


#messagescontainerrow 
        flex: 1;
        border: 5px double black;
    

#leftdiv 
        display:flex;
        flex-direction:column;
        border: 1px solid green;
    

#messagetools 
        height: 50px;
        background-color: cornsilk;
    

#messagelist 
        flex:1;     
        overflow-y: scroll;   
        background-color:whitesmoke;
    

#rightdiv 
        display:flex;
        flex-direction:column;
        border: 1px solid blue;
    

#messagesenderspane 
        width: 100%;
        height: 50px;
        background-color: lemonchiffon
    

#messagecontents 
        flex: 1;
        overflow-y: scroll; 
        width: 100%;
        border: 1px solid blue;
        background-color: aliceblue;
    

#messagesend 
        width: 100%;
        height: 70px;
        background-color: whitesmoke;
    
<html>
  <head>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css" rel="stylesheet"/>
  </head>
  <body>
    <div class="container body-content">
      <div class="row" id="messagescontainerrow">

        <div class="col-5" id="leftdiv">
            <div id="messagetools">
                <input type="button" id="newbutton" value="My Button" />
            </div>
            <div id="messagelist">
              <h4>Chat 1</h4>
              <h4>Chat 2</h4>
              <h4>Chat 3</h4>
              <h4>Chat 4</h4>
              <h4>Chat 5</h4>
              <h4>Chat 6</h4>
              <h4>Chat 7</h4>
              <h4>Chat 8</h4>
            </div>
        </div>


        <div class="col-7" id="rightdiv">
            <div id="messagesenderspane">
              Chat 3
            </div>
            <div id="messagecontents">
              <h4>line 1</h4>
              <h4>line 2</h4>
              <h4>line 3</h4>
              <h4>line 4</h4>
              <h4>line 5</h4>
              <h4>line 6</h4>
              <h4>line 7</h4>
            </div>
            <div id="messagesend">
                <textarea id="sendbox"></textarea>
                <input type="button" id="sendbutton" value="Send" />
            </div>
        </div>



      </div>
    </div>
  </body>
</html>

【问题讨论】:

【参考方案1】:

简答

请使用flex: 1 1 1px,而不是flex: 1

在您的代码中进行这两项调整:

#messagelist 
        /* flex:1; */
        flex: 1 1 1px; /* new */
    

#messagecontents 
        /* flex:1; */
        flex: 1 1 1px; /* new */
    

revised codepen


说明

在大多数情况下,正如您所指出的,将min-height: 0 添加到列方向容器中的弹性项目就足以解决问题。

然而,在这种情况下,还有一个额外的障碍:flex-basis

您将以下规则应用于弹性项目#messagelist#messagecontentsflex: 1

这是一条简写规则,可分解为:

flex-grow: 1 flex-shrink: 1 flex-basis: 0

(来源:https://www.w3.org/TR/css-flexbox-1/#flex-common)


2019 年更新: 自 2018 年发布此答案以来,Chrome 的行为似乎发生了变化,现在与 Firefox 和 Edge 保持一致。请在阅读本答案的其余部分时记住这一点。


在 Chrome 中,flex-basis: 0 足以触发溢出,从而生成滚动条。 (2019 年更新:This may no longer be the case。)

然而,在 Firefox 和 Edge 中,零 flex-basis 是不够的。就标准合规性而言,这可能是更正确的行为MDN states:

为了使overflow 生效,块级容器必须设置高度(heightmax-height)或将white-space 设置为nowrap

好吧,flex-basis: 0 不满足这些条件,因此不应发生溢出条件。 Chrome 可能参与了 intervention (as they often do)。

干预是指用户代理决定稍微偏离标准化行为以提供显着增强的用户体验。

为了满足“标准化行为”,这会导致在 Firefox 和 Edge 中发生溢出,给 flex-basis 一个固定的高度(即使它只有 1px)。

【讨论】:

您的解决方案显然有效(谢谢),但我还没有完全理解。我明白你对要求块级容器设置高度(高度或最大高度)或空白设置为 nowrap 的规范的意思。我不明白 flex-basis:0 如何满足该要求。 flex-basis 是否被认为是高度的有效替代品,因为否则它会优先于高度? 真正重要的不是flex-basis(它是height 的有效替代品)。这是您需要关注的0 值。 overflow 需要固定高度。 0 不满足该要求。但无论如何,Chrome 都能让它工作。 感谢您的帮助 Michael_B。我学到了一些关于弹性盒子的新东西(我不知道弹性基础是什么)。将此标记为解决方案。我还想出了一个不同的解决方案,我已经添加了一个单独的答案。 感谢您的回答!在过去的 10 个小时里,我一直在为此苦苦挣扎。最后我google了一下,找到了这个链接。 另见related problem / solution。似乎无关紧要,如果是 01px 来“开始成长”,只要它不是“面向儿童”的汽车......(现在只在 Chrome 中工作,这提醒我的 IE10 错误,其中 "min-width: 0" 是跨浏览器问题的标准解决方案 :-))【参考方案2】:

我将 Michael_B 的答案标记为正确答案,因为它是一个有效的解决方案以及解释。另外这里是我想出的另一个解决方案,不需要修改flex-basis:

#messagescontainerrow 
        flex: 1;

        min-height: 0;   /* ADDED THIS. */

        border: 5px double black;
    

#leftdiv 
        display:flex;
        flex-direction:column;

        max-height: 100%; /* ADDED THIS */

        border: 1px solid green;
    

#rightdiv 
        display:flex;
        flex-direction:column;

        max-height: 100%; /* ADDED THIS */

        border: 1px solid blue;
    

说明:

按照当前的 Flexbox 规范https://www.w3.org/TR/css-flexbox-1/#min-size-auto

一般来说,弹性项目的自动最小尺寸是较小的 其内容大小及其指定大小。但是,如果盒子有 纵横比且没有指定尺寸,其自动最小尺寸为 其内容大小和传输大小中的较小者。如果盒子有 既不是指定的大小也不是纵横比,它的自动最小值 size 是内容大小。

因此,默认情况下 #messagescontainerrow 会根据其内容采用最小高度,而不是尊重其父 flexbox 的高度。可以通过设置 min-height:0 来覆盖此行为。

通过进行此更改,您可以看到下图中显示的内容;请注意,@messagescontainerrow - 带有双线边框的那个 - 现在与其父级的高度相同 - 带有紫色虚线边框的那个。

(请注意,最新的规范草案,可在此处找到 - https://drafts.csswg.org/css-flexbox/#min-size-auto - 说“对于滚动容器,自动最小大小为零”。所以将来我们可能不需要这样做)。

现在剩下的问题是它的子项#leftdiv 和#rightdiv 超出了它的边界。正如 Michael_B 指出的那样,overflow 需要存在 heightmax-height 属性。因此,下一步是将max-height: 100% 添加到#leftdiv 和#rightdiv,以便触发其子级的overflow-y:scroll 属性。

结果如下:

【讨论】:

以上是关于防止弹性项目超过父高度并使滚动条工作的主要内容,如果未能解决你的问题,请参考以下文章

弹性盒子Flex Box滚动条原理,避免被撑开,永不失效

CSS弹性盒子布局flex

滚动条挤占内容宽度,影响布局

无限滚动时防止滚动条跳跃

当输入框大于tkinter中的窗口高度时,我们如何添加滚动条?

div 上的滚动条只有在它有超过 30 个项目时才会出现