Understanding flexbox and overflow:auto [duplicate] - css

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
In the following questions, I've been able to get all the cases to work out, I'm just looking to debug my mental model. I'm also only concerned with Chrome, if that makes answering easier.
I have an overflow:auto within nested "holy grail-ish" flexbox layouts. The overflow:auto behavior works fine for 2-level and 3-level nesting.
However, once I get to 4-level nesting, it "breaks," requiring me to specify the min-height:0 property (despite my having consistently specified flex-basis:0 via flex:1, which should annul the flex-basis:content/content-sized default). Why is this only happening at 4-level nesting?
Also, the element I need to slap the min-height:0 onto is .orange. Why this element, and why not the other ancestors?
Can anyone explain the above two questions? I have been consulting the spec and am having trouble connecting its rules back to my 4-level-deep example.
Note that this is different from the other questions I've been able to find on SO regarding flexbox and overflow, for instance (see in particular my answers):
overflow: auto in nested flexboxes
Nested flexbox with scrolling area

I have an overflow:auto within nested "holy grail-ish" flexbox layouts. The overflow:auto behavior works fine for 2-level and 3-level nesting.
Your 2-level code does indeed work as intended in Chrome, and IE11. However, it fails in Firefox. Same thing with your 3-level code: Works in Chrome and IE11, but not Firefox.
However, once I get to 4-level nesting, it "breaks," requiring me to specify the min-height:0 property (despite my having consistently specified flex-basis:0 via flex:1, which should annul the flex-basis:content/content-sized
default). Why is this only happening at 4-level nesting?
Once again, your statement is true for Chrome and IE11, but not for Firefox.
Solutions
Let's start with the fixes, so that all demos work in Chrome, Firefox and IE11. (I didn't test in Safari, but that's WebKit like Chrome, so it should be fine with vendor prefixes for any versions prior to 9.)
Also, I'll use compiled code in the answer, as not everybody uses preprocessors.
Revised 2-level (added two lines of code)
.violet {
flex: 1;
background: violet;
display: flex;
flex-direction: column;
min-height: 0; /* new */
min-width: 0; /* new */
}
Revised 3-level (added four lines of code)
.violet {
flex: 1;
background: violet;
display: flex;
flex-direction: column;
min-height: 0; /* new */
min-width: 0; /* new */
}
.orange {
flex: 1;
background: orange;
display: flex;
min-height: 0; /* new */
min-width: 0; /* new */
}
Revised 4-level (added one line of code)
.violet {
flex: 1;
background: violet;
display: flex;
flex-direction: column;
/* For some reason this is not needed */
/* min-height:0; */
min-width: 0; /* new */
}
Breaking Down the Behavior
There's a lot going on with your nesting. I'm not going to debug the code line-by-line, but I'll offer three concepts that may be useful to you.
1. Calculating Percentage Heights
Chrome, Firefox and IE11 can have different interpretations for an element's height.
Here's what it says in the spec:
CSS height property
percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to "auto".
auto The height depends on the values of other properties.
Traditionally, when calculating percentage heights, browsers have interpreted the spec's use of the term "height" to mean the value of the height property.
Based on a reading of the height definition, the interpretation could just as easily be the computed height, but the height property requirement has become the predominant implementation. I've never seen min-height or max-height work on a parent when dealing with percentage heights.
Chrome expects to see the height property when calculating height. If it doesn't, it computes the height to auto. Firefox, however, has a broader interpretation of the spec. It accepts flex heights, as well (as evidenced here and here and here).
It's not clear which browsers are more compliant.
It doesn't help matters that the height property definition hasn't been updated since 1998 (CSS2).
In all three of your demos you're combining percentage heights, pixel heights and flex heights. You may want to keep the differing browser interpretations in mind when troubleshooting your code.
Here are some more details: Working with the CSS height property and percentage values
2. Why doesn't flex item shrink past content size?
3. flex-basis: 0 vs flex-basis: auto
flex: 1 1 auto (or flex: auto, for short), sizes a flex item based on the content size or height properties.
flex: 1 1 0 (or flex: 1, for short), sizes a flex item based on the free space in the flex container.
Each may have a different effect on the behavior of overflow: auto.
More details here: Page-filling flexbox layout with top and side bars not quite working

Related

Different behavior of flexbox with (overflow-y) scroll on Safari, Firefox and Edge VS Chrome

In this page on plunker (https://plnkr.co/edit/gMbgxvUqHNDsQVe4P7ny?p=preview) there is a weird problem.
On Chrome on Windows and Android (Canary also) everything works good. I can scroll the two areas (on the left and on the right) and the top and bottom div of the page are on the top and on the bottom of my device screen. I see them anytime (see the picture below).
On iPad or iPhone, iOS, with Safari or Chrome, this is not what I get. And also on Firefox 47.0.1 on Windows.
The page is long and there is just one scroll on the right, like if there is no flexbox on the page, this code is just ignored:
.bigone {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.main {
flex: 1 1 0;
display: flex;
}
.container-fluid {
display: flex;
}
.col-6 {
overflow-y: auto;
}
Quirk example:
You can see on the iPad or iPhone just by a click on this button:
Why this behaviour?
Safari and Firefox bug or Chrome's one?
Why on Chrome everything good on Windows and Android?
And if in the new Safari in the future this will work good, how to do with the older devices with older iOS and firefox?
I will appreciate any answer. Thanks.
It's both a frustrating and mysterious problem.
The source of the problem in these sorts of questions is normally the minimum sizing algorithm on flex items. These rules, which are part of the spec, prevent a flex item from shrinking past the size of its content. Such behavior prevents a scrollbar from rendering because the content cannot overflow a flex item. It simply expands it.
But none of the standard methods to override that behavior (e.g., min-height: 0, overflow: hidden) seem to work in this case.
Here are two suggestions that may get you closer to a solution:
(1) Since you want the entire layout to appear in the viewport (i.e., no vertical scrollbar on the browser window), don't use min-height to size the container. That allows the container to expand. Use a fixed height instead.
Make this adjustment to your code:
.bigone {
display: flex;
/* min-height: 100vh; <-- REMOVE */
height: 100vh; /* <-- NEW */
flex-direction: column;
}
But that, by itself, doesn't solve the problem.
(2) A simple and quick solution to the problem is to set a height on .col-6.
Add this to your code:
.col-6 {
height: 90vh;
}
So it would appear that Edge, FF and the other "non-working" browsers need a defined height on that container.
revised demo
The Michael_B's answer is not enough. 90vh doesn't work with dynamic header, footer and other divs.
I fixed this (temporarily, until Safari fix this) with this on parent div:
min-height: 100vh; height: 100vh;
and
flex: 1; min-height: 0;' on the first children.
But the smell is heavy.
Try:
margin: auto;
in the css for the flex-item - that did the trick for me (seems like the auto does the magic here ...)
Wanted to share that finding, as min-height, overflow-x, etc ... did not work reliably for me neither.

CSS: Scrolling divs in a flexbox broken on IE11?

I have this layout. A container div set to
.container {
width: 80vw;
max-height: 75vh;
margin: auto;}
Inside that is a panel div with header and body divs, then my nested flexboxes. See image below:
The main flexbox div is set to row, with 2 divs in it which are flexbox column.
Inside those there is one div each which has overflow-y set to scroll, and they both have a lot of content.
This is working perfectly in Chrome and Safari, but in IE11 the scrolling divs do not scroll -- they go to the full height of their content and spill out of the container.
To be clear: only those divs in yellow should scroll.
What am I missing here?
Update
I have created a stripped-down pen: http://codepen.io/smlombardi/pen/reodZE?editors=1100
I see this question already has an accepted answer, but that solution didn't work for me. Something else did so I thought I would share for anyone encountering this in future.
My layout was very similar to this. There was a lot of nesting. Getting it to work in Chrome was quite straight forward. However, getting it to work in Firefox would take me another day of research & experimentation. In hindsight, it was probably because I didn't understand flex-box well enough.
To get a more complicated flex-box layout working cross-browser (by working, I mean flex children scrolling for overflowing content), do the following:
give outermost container a predefined height
use Flexbox for all containers that wrap the scrollable container
Since content lays vertically on the page by default, it's recommended to use: flex-direction: column
for Firefox: explicitly set min-height: 0 for every flex-item parent all the way up to the outermost flex-box.
if you have multiple flex children and the child that will scroll needs to expand to fill all available space, use flex-grow: 1
I got this from an article by Stephen Bunch, which I think was originally posted somewhere on SO too. Kudos to him!
Still, your scrolling flex child container will not work in IE11. It will expand to the full height of the contained content.
To fix it in IE11, do this:
Add overflow: hidden; to all its parents
Thanks to the original poster geon on SO in another related question.
Also, having a diagram of the flex layout was vastly more helpful than giant walls of code while researching to fix my own flex layout issues. Thanks OP!
Hoped that helped. It certainly did for me. All my flex-box issues for this more complicated layout.
PS: if this didn't solve it for you, maybe consider this list of flex-box bugs and their workarounds / solutions: https://github.com/philipwalton/flexbugs
Not sure if this is the best way, but I simplified this down to a simple bootstrap row, 2 columns.
I set the container to 75vh, and the 2 columns to the same 75vh.
The key was to set the 2 scrolling divs to flex-basis: something rem:
.search-results {
overflow-y: scroll;
margin-bottom: 10px;
flex-basis: 10rem;
background-color: #c4decf;
}
.accordions {
overflow-y: scroll;
overflow-x: hidden;
flex-basis: 40rem;
flex-grow: 1;
background-color: #f0f0f0;
padding: 10px;
}
See updated codepen: http://codepen.io/smlombardi/pen/WwLgyV?editors=1100
None of the answers here worked for me.
My experience with IE is that both inheritance and properties needs to be set explicitly a lot of the time and the same was true here.
The fix in my case was then to set the max height of container element to 90vh and overflow-y to hidden.
The child element (scroll element) was set to inherit the max-height with overflow-y set to auto. Simply setting it to 100% did not work, really the keyword was "inherit"
all other parent elements got overflow hidden

Flex inside flex doesent work in Firefox 38

I try to use flex in firefox, it doesent work, in Chrome, it works like a charm!
Here is the result in Firefox:
And here is how it looks (should look) in Chrome/Opera:
What is the problem?
Here is the CSS, that doesent work on Firefox:
.jawcontain {display: flex;flex-direction: column;justify-content: space-between;border: white solid 7px;border-radius: 23px;}
.jaw {background-color: rgb(24, 24, 24);border-radius: 5%;display: flex;flex-direction: row;padding-top: 2%;padding-bottom: 5%;border: 10px solid rgb(0, 151, 255);justify-content: space-around;}
.hala {border: white solid 2px;padding-left: 10%;border-radius: 5%;margin-right: 2% display: flex;flex-basis: 40%;flex-direction: column;background: black;justify-content: space-around;}
The problem is that .jaw are flex items, and you use
.jaw {
padding-top: 2%;
padding-bottom: 5%;
}
In CSS 2.1, percentages in padding were specified as
The percentage is calculated with respect to the width of the
generated box's containing block, even for 'padding-top' and 'padding-bottom'.
However, in Flexible Box Layout Module,
Percentage margins and paddings on flex items are always resolved
against their respective dimensions; unlike blocks, they do not always
resolve against the inline dimension of their containing block.
Therefore, Firefox attempts to resolve those percentages with respect to the height of the flex container. But that height is auto, that is, it depends on the height of the content, including the vertical paddings. It's a circular definition, so the paddings compute to 0.
But Chrome does not agree, and resolves the percentages with respect to the width of the flex container. The spec warns about that:
Note: This behavior is currently disputed, and might change in a
future version of this specification to match the behavior of blocks.
Since you don't seem to be using flex, you can remove
.jawcontain {
display: flex;
}
Then, .jaw will no longer be flex items, and the paddings will be resolved with respect to the width of the containing block.

IE vertical centering bug with table-cell parent and absolutely positioned pseudo-element

I'm building a flexible progress-bar with a number of constraints. It needs to be able to contain any number of items within it, have these items all be the same width, vertically centered, support content of varying lengths, work in IE9 and above and have an icon next to them without any additional markup. display: table-cell seemed to be the most appropriate solution for the potentially unlimited number of items inside as well as vertically aligning the text nicely, and :before would take care of the icon, which would also be vertically aligned with the top: 50%; translateY(-50%) method.
This seemingly works fine on modern browsers, as there's nothing particularly fancy here. However, in any version of Internet Explorer, this isn't going as smoothly as I'd like. If the items are of a variable height, the icons aren't vertically centered on anything but the tallest element. IE9 has support for translateY and it's been ages since we had difficulties with display: table/table-cell. Even IE11 can't make this work.
I have created a reduced test case on CodePen so you can see it in action:
Here's a screenshot of the method working perfectly in Firefox:
And failing in IE11:
I initially thought the failure was due to the height of the elements not being calculated correctly in IE, but the borders being uniform indicates that this isn't the case.
If I set the list items to display: inline-block and manually set their widths, the icon vertically centers as expected, but I'd like to retain the more flexible behavior of table-cell display, if at all possible.
Any insights would be greatly appreciated. Thanks in advance!
The issue seems to be with how IE is calculating the heights of the cells. Their heights seem to be based on the height of the contents, not the element itself. So I moved the relative positioning to the list itself as its intrinsic height should be consistent:
.progress-bar {
display: table;
table-layout: fixed;
width: 100%;
position: relative;
counter-reset: progressBar;
}
Then I positioned the check in a slightly different manner using your top offset of 50%, but leaving the left offset to “auto” and using negative margins to move it into place (since they have better backward-compatible support than transform), but that choice is up to you:
&:before {
content: "✓";
color: green;
display: block;
position: absolute;
top: 50%;
margin-top:-.5em;
margin-left: -1em;
}
I hope this helps.
Here’s the Codepen fork: http://codepen.io/aarongustafson/pen/PwPxEp

Display table is exceeding parent height in every browser but Chrome

I'm trying to stack 2 divs of variable height one on top of the other. Both divs combined should not exceed the container height. The 2nd div should allow scrolling if it gets too big.
I've done some research on how to make a div take the remaining height and it pointed me towards display: table-row. I can't use absolute positioning because I don't know what the height of the 1st div will be as it is also variable.
The problem appears to be that the table will always expand vertically with the content unless I use a fixed height on one of the divs.
Here's a JSBin of the problem: http://jsbin.com/heyam/3/edit?html,css,output
It works fine in Chrome but doesn't work in any other browser. I've read dozens of threads on SO with similar problems but none of the answers gave me a working solution. My browser support includes the latest versions of FF, Chrome, Safari and IE9+.
Is there a CSS-only solution to this problem or am I stuck using JS on this one?
.slideout {
display: table;
float:right;
width: 200px;
height: 100%;
background: blue;
}

Resources