Prevent flex item from exceeding parent height and make scroll bar work
Short Answer
Instead of flex: 1
, use flex: 1 1 1px
.
Make these two adjustments in your code:
#messagelist {
/* flex:1; */
flex: 1 1 1px; /* new */
}
#messagecontents {
/* flex:1; */
flex: 1 1 1px; /* new */
}
revised codepen
Explanation
In most cases, as you have noted, adding min-height: 0
to flex items in a column-direction container is enough to correct the problem.
In this case, however, there's an additional obstacle: flex-basis
.
You're applying the following rule to flex items #messagelist
and #messagecontents
: flex: 1
.
This is a shorthand rule that breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
(source: https://www.w3.org/TR/css-flexbox-1/#flex-common)
2019 UPDATE: Since the posting of this answer in 2018, it appears that Chrome's behavior has changed and is now uniform with Firefox and Edge. Please keep that in mind as you read the rest of this answer.
In Chrome, flex-basis: 0
is enough to trigger an overflow, which generates the scrollbars. (2019 update: This may no longer be the case.)
In Firefox and Edge, however, a zero flex-basis
is insufficient. This is probably the more correct behavior in terms of standards compliance as MDN states:
In order for
overflow
to have an effect, the block-level container must have either a set height (height
ormax-height
) orwhite-space
set tonowrap
.
Well, flex-basis: 0
meets none of those conditions, so an overflow condition should not occur. Chrome has probably engaged in an intervention (as they often do).
An intervention is when a user agent decides to deviate slightly from a standardized behavior in order to provide a greatly enhanced user experience.
To meet the "standardized behavior", which would enable an overflow to occur in Firefox and Edge, give flex-basis
a fixed height (even if it's just 1px).
CSS Flex Overflow
You have a couple of fixed lengths in your code, including:
.side {
width: 224px;
}
.topbar {
height: 100px;
}
These hard limits make the solution to overflow problems relatively simple, since the easiest way to trigger a scrollbar is to create an overflow condition, which is best accomplished with a fixed length.
In this case, the .topbar { height: 100px }
is the key to the scrollbar on the sibling element.
(Note that you need to disable flex-shrink
on these lengths for the values to always be respected.)
Here's a revised version of your code, with various adjustments for greater performance and efficiency.
body { margin: 0; background-color: black;}
.wrapper { display: flex; height: 100vh;}
.side { /* width: 224px; */ /* will not be respected without adding `flex-shrink: 0` */ flex: 0 0 224px; /* new; flex-grow, flex-shrink, flex-basis */ background-color: blue; display: flex; flex-direction: column;}
.content-wrapper { flex: 1; /* consume remaining space */ display: flex; flex-direction: column;}
.wrapper .content-wrapper .content { display: flex; flex-direction: column;}
.topbar { flex: 0 0 100px; /* height: 100px; */ background-color: aqua;}
.main { height: calc(100vh - 100px); /* new; sets overflow condition */ background-color: pink; display: flex;}
.header { background-color: yellow; overflow-y: scroll; /* height: 100%; */}
.details { background-color: crimson;}
.item { background-color: white; border-style: solid; height: 200px; /* not a flex item, so no need to disable flex-shrink */}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/><div class="wrapper"> <div class="side"></div> <div class="content-wrapper"> <div class="content"> <div class="topbar"></div> <div class="main"> <div class="header col-lg-4"> <div class="item">item</div> <div class="item">item</div> <div class="item">item</div> <div class="item">item</div> <div class="item">item</div> <div class="item">item</div> <div class="item">item</div> </div> <div class="details col-lg-8"></div> </div> </div> </div></div>
How can I prevent last flex item from overflowing parent
Give a height: 100%;
to the .panel-popover-window
container.
* { box-sizing: border-box;}
.panel-popover-window { background-color: grey; border-bottom: 1px solid black; display: flex; flex-direction: column; width: 1200px; height: 100%;}
.panel-popover-title-bar { border: 1px solid black; width: 100%; height: 50px; line-height: 50px; padding: 0 20px; position: relative;}
.panel-popover-content { display: flex; flex-direction: row; flex-grow: 1; flex-shrink: 1; padding: 5px; min-height: 0; overflow-y: scroll;}
.panel-popover-column-2 { display: flex; flex-direction: column; flex: 0 0 50%;}
.panel-popover-panel { border: 1px solid #e0e0e0; margin: 5px; background-color: #fff;}
.panel-popover-panel-title { display: block; border-bottom: 1px solid black; width: 100%; height: 50px; padding: 0 10px; position: relative;}
.panel-popover-footer { min-height: 60px; padding: 0 10px;}
.panel-popover-footer-content { position: relative;}
.panel-popover-footer-button-bar { width: 100%; height: 60px;}
.panel-popover-close-button { border: 1px solid black; width: 83px; height: 37px; float: right; margin-top: 15px;}
.detail-chat-input { min-height: 48px; border: 1px solid black; border-radius: 5px; background-color: #fff; padding: 10px; width: 100%; font-size: 15px; line-height: 30px;}
.detail-activity-scrollable { overflow-y: scroll; height: calc(100% - 50px);}.detail-message-container { min-height: 800px;}
.panel-popover-panel.activity { max-height: 685px; overflow-y: hidden; position: relative;}
<html> <head> </head> <body> <div class="panel-popover-window detail-popover"> <div class="panel-popover-title-bar"> <span class="panel-popover-title-bar-text">Popover Title</span> <div class="panel-popover-title-bar-close"></div> </div> <div class="panel-popover-content"> <div class="panel-popover-column panel-popover-column-2"> <div class="panel-popover-panel submission-info"> <div class="panel-popover-panel-title">Title 1</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> </div> <div class="panel-popover-panel statistics"> <div class="panel-popover-panel-title">Title 2</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> <div class="ad-approval-panel-line">Data</div> </div> </div> <div class="panel-popover-column panel-popover-column-2"> <div class="panel-popover-panel activity"> <div class="panel-popover-panel-title">Title 3</div> <div class="detail-activity-scrollable"> <div class="detail-message-container"> <div class="ad-approval-panel-line">Data</div> </div> </div> </div> </div> </div> <div class="panel-popover-footer"> <div class="panel-popover-footer-content"> <textarea class="detail-chat-input" placeholder="Send Message" data-emojiable="converted" style="display: none;" data-id="8ff80f0d-85e3-4ac4-acbf-c950fffbc1a4" data-type="original-input"></textarea> <div class="emoji-wysiwyg-editor detail-chat-input parent-has-scroll" placeholder="Send Message" contenteditable="true"></div> <div class="panel-popover-footer-button-bar"> <button class="detail-admin-control detail-approve" disabled="">Button 1</button> <button class="detail-admin-control detail-disapprove">Button 2</button> <div class="panel-popover-close-button">Close</div> </div> </div> </div> </div> </body></html>
Flexbox: how to not overstretch a nested flexbox by an oversized child element (along cross axis)
Put height: 100%;
to .one, .two
so your flex elements will only get the available space in height
(Addition by Questioner.)
Interesting, there appear to be 3 solutions to this:
1) to .one
add (also to .two
won't hurt, and probably a good idea recalling IE-crossbrowser-issues)
min-height: 0;
2) to both .one, .two
add:
height: 100%;
3) to .one
add (also to .two
won't hurt. Won't truncate borders on children btw (which is a good sign), still all properly visible on all edges)
overflow: hidden;
Imho (1) is the "cleanest" solution... (as it fixes the root cause, probably also the safest bet against cross-browser-issues)
Prevent a child element from overflowing its parent in flexbox
An initial setting on flex items is min-width: auto
. This means that a flex item, by default, cannot be smaller than the size of its content.
Therefore, text-overflow: ellipsis
cannot work because a flex item will simply expand, rather than permit an overflow. (Scroll bars will not render either, for the same reason.)
To override this behavior, use min-width: 0
or overflow: hidden
. More details.
#container { display: flex; flex-wrap: wrap; border: thin solid gray;}
.card-wrapper { width: 33.33%; display: flex; background: #e0e0ff;}
.card { flex-grow: 1; margin: 7px; display: flex; flex-direction: column; border: thin solid gray; background: #e0ffff; overflow: hidden; /* NEW */}
.card div { border: thin solid gray;}
.card div:nth-child(1) { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; /* NEW */}
.card div:nth-child(2) { flex-grow: 2;}
<div id="container"> <div class="card-wrapper"> <div class="card"> <div>Title</div> <div>Multiline<br/>Body</div> <div>Footer</div> </div> </div> <div class="card-wrapper"> <div class="card"> <div>Really long rambling title that pushes beyond the bounds of the container, unless your screen is really, really wide</div> <div>Body</div> <div>Footer</div> </div> </div> <div class="card-wrapper"> <div class="card"> <div>Title</div> <div>Body</div> <div>Footer</div> </div> </div> <div class="card-wrapper"> <div class="card"> <div>Title</div> <div>Body</div> <div>Footer</div> </div> </div> <div class="card-wrapper"> <div class="card"> <div>Title</div> <div>Body</div> <div>Footer</div> </div> </div></div>
Trick to prevent child from stretching parent flexbox doesn't work on all browsers
Looks like the solution is:
Don't use the trick!
If you replace height: 0;
with a simple flex: 1 1 0
, it will work perfectly.
Just remember to not add the %
symbol to the trailing 0
(which is the default behavior if you use the shorthand flex: 1
).
Related Topics
iOS 7 iPad Safari Landscape Innerheight/Outerheight Layout Issue
Make Child Visible Outside an Overflow:Hidden Parent
How to Transition CSS Display + Opacity Properties
What Is the Meaning of 'Auto' Value in a CSS Property
Automatically Resize Images with Browser Size Using CSS
Ampersand (&) at the End, and Part of, a Selector in SASS
Google Chrome A:Visited Background Image Not Working
How to Vertically Align <Li> Elements in <Ul>
What Does an "&" Before a Pseudo Element in CSS Mean
Svg in Img Element Proportions Not Respected in IE9
Expand Div from the Middle Instead of Just Top and Left Using CSS
Responsive CSS Styles on Mobile Devices Only
Why Is @Font-Face Throwing a 404 Error on Woff Files
Creating CSS Global Variables:Stylesheet Theme Management