firefox overflow-y not working with nested flexbox

36,655

tl;dr: you need min-height:0 in your .level-0-row2 rule. (Here's a codepen with that fix.)

More detailed explanation:

Flex items establish a default minimum size that's based on their children's intrinsic size (which doesn't consider "overflow" properties on their children/descendants).

Whenever you've got an element with overflow: [hidden|scroll|auto] inside of a flex item, you need to give its ancestor flex item min-width:0 (in a horizontal flex container) or min-height:0 (in a vertical flex container), to disable this min-sizing behavior, or else the flex item will refuse to shrink smaller than the child's min-content size.

See https://bugzilla.mozilla.org/show_bug.cgi?id=1043520 for more examples of sites that have been bitten by this. (Note that this is just a metabug to track sites that were broken by this sort of issue, after this spec-text was implemented -- it's not actually a bug in Firefox.)

You won't see this in Chrome (at least, not as of this posting) because they haven't implemented this minimum sizing behavior yet. (EDIT: Chrome has now implemented this min-sizing behavior, but they may still incorrectly collapse min-sizes to 0 in some cases.)

Share:
36,655
rekna
Author by

rekna

Updated on July 22, 2021

Comments

  • rekna
    rekna almost 3 years

    I have designed a 100% width 100% height layout with css3 flexbox, which works both on IE11 (and probably on IE10 if emulation of IE11 is correct).

    But Firefox (35.0.1), overflow-y is not working. As you can see in this codepen : http://codepen.io/anon/pen/NPYVga

    firefox is not rendering overflow correctly. It shows one scrollbar

    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
      border: 0;
    }
    .level-0-container {
      height: 100%;
      display: -webkit-box;
      display: -webkit-flex;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-orient: vertical;
      -webkit-box-direction: normal;
      -webkit-flex-direction: column;
      -ms-flex-direction: column;
      flex-direction: column; 
    }
    .level-0-row1 {
      border: 1px solid black;
      box-sizing: border-box;
    }
    .level-0-row2 {
      -webkit-box-flex: 1;
      -webkit-flex: 1;
      -ms-flex: 1;
      flex: 1;
      border: 1px solid black;
      box-sizing: border-box;
      display: -webkit-box;
      display: -webkit-flex;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-orient: horizontal;
      -webkit-box-direction: normal;
      -webkit-flex-direction: row;
      -ms-flex-direction: row;
      flex-direction: row;
    }
    .level-1-col1 {
      width: 20em;
      overflow-y: auto;
    }
    .level-1-col2 {
      -webkit-box-flex: 1;
      -webkit-flex: 1;
      -ms-flex: 1;
      flex: 1;
      border: 4px solid blue;
      box-sizing: border-box;
      display: -webkit-box;
      display: -webkit-flex;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-orient: vertical;
      -webkit-box-direction: normal;
      -webkit-flex-direction: column;
      -ms-flex-direction: column;
      flex-direction: column;
    }
    .level-2-row2 {
      -webkit-box-flex: 1;
      -webkit-flex: 1;
      -ms-flex: 1;
      flex: 1;
      border: 4px solid red;
      box-sizing: border-box;
      overflow-y: auto;
    }
    <html>
    <body>
    
        <div class="level-0-container">
    
            <div class="level-0-row1">
                Header text
            </div>
    
            <div class="level-0-row2">
    
                <div class="level-1-col1">
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    line <br/>
                    
                </div>
    
                <div class="level-1-col2">
    
                        <div class="level-2-row1">
                            Some text
                            <p/> Some text 2
                            <p/> Some text 3
                            <p/> 
                        </div>
    
                        <div class="level-2-row2">
                            <p>some text</p>
                            <p>some text</p> 
                            <p>some text</p> 
                            <p>some text</p>
                            <p>some text</p>
                            <p>some test</p>
                        </div> 
                    </div>
    
            </div>
    
        </div>
    </body>
    
    
    </html>
  • Ambroz Bizjak
    Ambroz Bizjak about 8 years
    I've hit this issue but I had to add min-height:0 to all the parent flexbox columns - any idea why?
  • Sam Storie
    Sam Storie about 8 years
    Does this min-height (in my case) need to be applied to every ancestor? Or just the immediate parent?
  • dholbert
    dholbert almost 8 years
    It potentially needs to be applied to every ancestor that is a flex item (i.e. every ancestor whose parent is display:flex), depending on the circumstances.
  • trysis
    trysis over 7 years
    Are there any plans to change the spec to take overflow into account? Now that I know why this happens I can work around it, but it will still be annoying.
  • dholbert
    dholbert over 7 years
    RE spec changes -- I asked about this on the CSS working group list, and the spec editor replied that "we don't think it's possible to address this in any sane way" (and I agree, given the primitives that CSS has to work with). lists.w3.org/Archives/Public/www-style/2014Aug/0282.html So you'll likely continue to need min-width:0 / min-height:0 hackarounds for situations like this, going forward.
  • Brett
    Brett over 7 years
    Any reason we can't just apply * { min-height: 0; min-width: 0; }?
  • dholbert
    dholbert over 7 years
    You could do that, but that would disable the Good Things that the magic min-width:auto behavior brings. In particular: flex items are set up to be shrinkable down to their resolved min-width (or min-height if vertical) by default, by virtue of having flex-shrink:1 in their initial style. So if you set min-width (or min-height) to 0, then your flex items will let themselves shrink down to 0 by default, which might not be what you want -- particularly if it's just because another greedy flex item is stealing all of the space.
  • dholbert
    dholbert over 7 years
    @Brett, here's a jsfiddle demonstrating the sort of badness (content overflowing/overlapping) that can arise from using min-width:0 too aggressively: jsfiddle.net/85scnr1b So really, you only want to add min-width:0 on flex items whose content can "behave nicely" if it's given an arbitrarily-smaller width than it expects. (Same goes for min-height & height, for vertical flex containers.)
  • Ashok Koyi
    Ashok Koyi about 7 years
    In my case even setting min-height on all ancestors is not working. I have to compute the height at runtime using window.getComputedStyle & calculate the height that can be taken by the scrollable area. I'm using chrome. Any reason why this might be the case?
  • Boog
    Boog over 6 years
    For whatever reason adding min-height:0px to my parent flex item resolved this issue for me, setting it on child-ancestors appeared to have no affect. Issue was only occurring in FF.