Chrome ignoring flex-basis in column layout

10,092

Three items to consider:

  • Sum of all heights greater than 100%

    In your .column layout, you have three flex items. Their heights are 75% + 25% + 50px. This by itself exceeds the height: 100% you applied. This does not cause an overflow because you have flex-shrink set to 1.

  • Margin space

    You have specified margin: 10px for both layouts. So there's an extra 20px of height from the top and bottom margins. In the .column layout, this does indeed cause an overflow on Chrome.

    Adjust for those extra 20px, and the overflow is gone:

    .column {
      flex-direction: column;
      height: calc(100% - 20px);   /* new */
    }
    

    .container {
      width: 400px;
      height: 200px;
      display: flex;
      background: #666;
      position: relative;
    }
    
    .layout {
      flex: 1 1 100%; /* within .container */
      margin: 10px;
      display: flex;
    }
    
    .row {
      flex-direction: row;
    }
    .column {
      flex-direction: column;
      height: calc(100% - 20px);   /* NEW */
    }
    
    .exact {
      flex: 1 1 50px;
      background: #ffc;
    }
    .small {
      flex: 1 1 25%;
      background: #cff;
    }
    .large {
      flex: 1 1 75%;
      background: #fcf;
    }
    <div class="container">
      <div class="layout column">
        <div class="exact">50px</div>
        <div class="small">25%</div>
        <div class="large">75%</div>
      </div>
      <div class="layout row">
        <div class="exact">50px</div>
        <div class="small">25%</div>
        <div class="large">75%</div>
      </div>
    </div>
  • Percentage Heights: Chrome / Safari vs Firefox / IE

    The reason the flex items in Chrome / Safari don't recognize their percentage heights is because Webkit browsers are adhering to a more traditional interpretation of 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.

    In other words, if you want an element to have a percentage height, then you must specify a height on the parent.

    The traditional interpretation of this language is that "height" means the value of the height property. Although it's unclear from the language exactly what "height" means, the height property requirement has been the predominant implementation. I've never seen min-height, max-height or other forms of height work on a parent when dealing with percentage values.

    Recently, however, as noted in this question (and another one and another one and another one), Firefox (and IE, apparently) has broadened its interpretation to accept flex heights, as well.

    It's not clear which browser is more compliant with the standard.

    It doesn't help matters that the height definition hasn't been updated since 1998 (CSS2).

    Bottom line, Chrome and Safari resolve percentage heights based on the value of the parent's height property. Firefox and IE11/Edge use the parent's computed flex height.

    For now, the simplest cross-browser solution to this problem would be, in my view, using the height property across the board for percentage heights.

    UPDATE: More solutions here: Chrome / Safari not filling 100% height of flex parent

Share:
10,092
medmunds
Author by

medmunds

Co-founder: Planapple travel-planning app (Django, JavaScript, etc.) Maintainer: Anymail Django bindings for transactional email service providers like Mailgun, Postmark, SendGrid and SparkPost Past lives: Eyefi, Macromedia, and more

Updated on June 16, 2022

Comments

  • medmunds
    medmunds almost 2 years

    I'm having trouble getting Chrome to pay attention to the flex-basis part of flex: 1 1 25% in a flex-direction: column layout. It works fine in a row layout.

    The snippet below demonstrates the problem: the yellow, blue, and pink bars are flex-basis 50px, 25%, and 75%, shown in both column and row flex directions.

    If you run it in Firefox (or IE11 or Edge) both column and row divide up the area as expected:

    Firefox screenshot

    But if you run it in Chrome (47) or Safari (9.0.3), the column layout on the left seems to ignore the flex-basis entirely -- the heights of the bars seem to have no relation to the flex-basis:

    enter image description here

    The only difference between left and right is the flex-direction.

    .container {
      width: 400px;
      height: 200px;
      display: flex;
      background: #666;
      position: relative;
    }
    
    .layout {
      flex: 1 1 100%; /* within .container */
      margin: 10px;
      display: flex;
    }
    
    .row {
      flex-direction: row;
    }
    .column {
      flex-direction: column;
    }
    
    .exact {
      flex: 1 1 50px;
      background: #ffc;
    }
    .small {
      flex: 1 1 25%;
      background: #cff;
    }
    .large {
      flex: 1 1 75%;
      background: #fcf;
    }
    <div class="container">
      <div class="layout column">
        <div class="exact">50px</div>
        <div class="small">25%</div>
        <div class="large">75%</div>
      </div>
      <div class="layout row">
        <div class="exact">50px</div>
        <div class="small">25%</div>
        <div class="large">75%</div>
      </div>
    </div>

    I tried adding height: 100% to .column, which makes Chrome pay attention to the flex-basis, but causes a different problem -- the flex gets bigger than its container:

    .column {
      flex-direction: column;
      height: 100%;
    }
    

    Chrome screenshot with height: 100%

    I gather this is a long-standing webkit bug. Is there any way to work around it? (I'm trying to create some generalized layout components, so hard-coding specific numbers of children or specific pixel heights isn't workable.)

    [EDIT] Here's an additional example showing the general problem (and avoiding the margin and total-greater-than-100% issues in the example above):

    Firefox vs Chrome nested flexboxes

    .container {
      width: 300px;
      height: 300px;
      display: flex;
    }
    
    .layout {
      flex: 1 1 100%; /* within its flex parent */
      display: flex;
      background: #ffc;
    }
    
    .row {
      flex-direction: row;
    }
    .column {
      flex-direction: column;
      height: 100%; /* attempted workaround for webkit */
    }
    
    .small {
      flex: 1 1 30%;
      background: #cff;
    }
    .large {
      flex: 1 1 70%;
      background: #fcf;
    }
    
    div {
      /* border/padding just makes divs easier to see --
         you can remove all of this without changing the problem */
      box-sizing: border-box;
      border: 1px solid #999;
      padding: 10px;
    }
    <div class="container">
        <div class="layout row">
            <div class="small">row: 30%</div>
            <div class="large layout column">
              <div class="small">row: 70%; col: 30%</div>
              <div class="large">row: 70%; col: 70%</div>
            </div>
        </div>
    </div>