36

I would like a column of divs, of any number, each with width 100% and height 100% of their parent div, so one is visible initially, and the others overflow the parent downwards. I've set the divs to have flex: 0 0 100%;, inside a parent div with display: flex and flex-direction: column to achieve this.

The parent div is itself of unknown height, so it is also a child of a display: flex and flex-direction: column, set to flex: 1 0 0 to take remaining space in its container.

In Firefox the output is as I would like it:

Firefox nested flex boxes

However, not in Chrome:

Chrome nested flex boxes

How can I achieve the Firefox style in Chrome, without Javascript?

You can see this in action at http://plnkr.co/edit/WnAcmwAPnFaAhqqtwhLL?p=preview, as well as the corresponding version with flex-direction: row, which works consistently in both Firefox and Chrome.

For reference, the full CSS

.wrapper {
  display: flex;
  flex-direction: column;
  height: 150px;
  width: 200px;
  border: 4px solid green;
  margin-bottom: 20px;
}

.column-parent {
  flex: 1 0 0;
  display: flex;
  flex-direction: column;
  border: 2px solid blue;
}

.column-child {
  flex: 0 0 100%;
  border: 2px solid red;
}

and HTML

<div class="wrapper">
  <p>Some content of unknown size</p>
  <div class="column-parent">
    <div class="column-child">
      Should be inside green
    </div>
    <div class="column-child">
      Should be outside green
    </div>
  </div>
</div>
Michal Charemza
  • 25,940
  • 14
  • 98
  • 165
  • notice that in firefox too - if you add additional column-child elements - they collapse (like in Chrome) [Plunker](http://plnkr.co/edit/BfDxsEPNmYgXoQnIgtt8?p=preview) – Danield Aug 18 '15 at 09:23
  • I have added another solution, less hacky, in my answer – vals Aug 23 '15 at 19:17
  • [Chrome / Safari not filling 100% height of flex parent](http://stackoverflow.com/q/33636796/3597276) – Michael Benjamin May 05 '17 at 20:20

4 Answers4

19

This seems to be a bug with Chrome. Similar to the ones reported here (issue 428049) and perhaps related to (issue 346275).

This says:

- Browsers are supposed to resolve percentages on the flex item's child, *if* its flex-basis is definite.
- Gecko is *always* resolving percentages regardless of the flex-basis.
- Chrome is *never* resolving percentages, regardless of the flex-basis. 

Summarily, Chrome is not resolving percent heights on flex-item's child (even if the child itself is a flex-item), while all other browsers do.

This can be demonstrated in the below snippet: (Fiddle here)

* { box-sizing: border-box; margin: 0; padding: 0; }
div.wrap {
    height: 120px; width: 240px; margin: 0px 12px;
    border: 1px solid blue; float: left;
    display: flex; flex-direction: column;    
}
div.parent {
    flex: 0 0 100%;
    border: 1px solid green; 
    display: flex; flex-direction: column;    
}
div.item {
    flex: 0 0 100%;
    border: 1px solid red;
}
<div class="wrap">
    <div class="item">a</div>
    <div class="item">b</div>
    <div class="item">c</div>
</div>
<div class="wrap">
    <div class="parent">
        <div class="item">a</div>
        <div class="item">b</div>
        <div class="item">c</div>
    </div>
</div>

The second div should show the same behaviour as the first one. Other browsers (IE11, Edge, FF39) show it correctly. Chrome fails here and does not resolve div.item correctly. It needs a fixed height on its parent, without which it uses min-content as its height and thus does not overflow.

Whereas, in the first div, the div.items are correctly resolved and overflow accordingly. This is because there is a fixed height on the parent (i.e. div.wrap)


Possible Solution:

As a workaround, if you are sure to have only two elements (p and div) inside your wrapper, then you could give them a 50% height. You have to provide a height:50% to your .column-parent. Chrome needs a fixed height on parent as demonstrated above.

Then everything will work as you need to.

Demo Fiddle: http://jsfiddle.net/abhitalks/kqncm65n/

Relevant CSS:

.wrapper > p { flex: 0 0 50%; }  /* this can be on flex-basis */
.column-parent {
    flex: 1 0 auto; height: 50%; /* but, this needs to be fixed height */
    display: flex; flex-direction: column;
    border: 2px solid blue;
}
.column-child {
    flex: 0 0 100%;              /* this flex-basis is then enough */
    border: 2px solid red;
}

PS: There also seem to be differences in the way jsfiddle and plnkr render. I don't know why, but sometimes I get different results!

Abhitalks
  • 27,721
  • 5
  • 58
  • 81
  • `HTML` is properly typed in [this fiddle](https://jsfiddle.net/xameeramir/6euozd0w/). What can be the reason for not printing values? – Zameer Ansari Dec 28 '15 at 08:16
16

As stated in Abhitalks response, there is a bug (or a different interpretation of the standard) in the way Chrome handles the height attribute here.

I have found a hack that is working both in Chrome FF and IE

The only issue is that you ned to have as many rules as posible children there are.

The trick is to set the flex-direction to row, set the flex-basis (that is now the width) to 100%, and then translate the elements

.container {
    border: solid 2px blue;
    height: 200px;
    width: 200px;
    display: flex;
    flex-direction: column;
    position: relative;
}

.filler {
    border: solid 1px black;
    flex: 0 0 80px;
    background-color: lightgreen;
    transition: flex 1s;
}

.container:hover .filler {
    flex: 0 0 40px;
}

.test {
    border: solid 1px red;
    flex: 1 0 25px;
    display: flex;
    flex-direction: row;
    position: relative;
}

.child {
    background-color: rgba(200, 0, 0, 0.26);
    flex: 0 0 100%; 
}

.child:nth-child(2) {
    background-color: rgba(255, 255, 0, 0.48);
    transform: translateX(-100%) translateY(100%);
}

.child:nth-child(3) {
    background-color: rgba(173, 216, 230, 0.28);
    transform: translateX(-200%) translateY(200%);
}
<div class="container">
    <div class="filler"></div>
    <div class="filler"></div>
    <div class="test">
        <div class="child">1</div>
        <div class="child">2</div>
        <div class="child">3</div>
    </div>
</div>

If there could be another child, you would need a nth-child(4) rule, and so on

I have added an hover effect to check how the size adapts

vals
  • 61,425
  • 11
  • 89
  • 138
  • I'm actually leaning to the solution you posted initially... can you post each in a separate answer? I think they seem sufficiently different to warrant that. – Michal Charemza Aug 23 '15 at 19:33
  • Hi ! I was going to split the answer, and I see that you have accepted it... Now I don't know much what to do. Feel free to edit it if you want :-) – vals Aug 24 '15 at 17:57
  • I think it would still be better to split it, just since they are such different solutions. I suspect that I will award the bounty to the one you posted first. – Michal Charemza Aug 24 '15 at 18:06
10

My previous answer is a hack that exploits a particular setup of the layout wanted.

An alternate way, more general, of getting around this Chrome bug is to use an intermediate element in the layout, and set this element size using top: 0px and bottom: 0px. (instead of height: 100%) There is still a bug in the way Chrome handles the calculus, that needs a fake animation to make it adjust properly

.container {
    border: solid 2px blue;
    height: 200px;
    width: 200px;
    display: flex;
    flex-direction: column;
    position: relative;
}

.filler {
    border: solid 1px black;
    flex: 0 0 94px;
    background-color: lightgreen;
    transition: 1s;
}

.container:hover .filler {
    flex: 0 0 50px;
}

.test {
    border: solid 1px red;
    flex: 1 0 25px;
    display: flex;
    flex-direction: row;
    position: relative;
}

@-webkit-keyframes adjust2 {
    0% {flex-basis: 100%;}
  100% {flex-basis: 100.1%;}
}
.child {
    background-color: rgba(200, 0, 0, 0.26);
    width:  100%;
    height: 100%;
    flex: 1 0 100%;
    -webkit-animation: adjust2 1s infinite; /* only needed for webkit bug */
}

.intermediate {
    width:  100%;
    position: absolute;
    top: 0px;
    bottom: 0px;
    display: flex; 
    flex-direction: column; 
}

.child:nth-child(n+2) {
    background-color: rgba(255, 255, 0, 0.48);
}

.child:nth-child(n+3) {
    background-color: rgba(173, 216, 230, 0.28);
}
<div class="container">
    <div class="filler"></div>
    <div class="test">
        <div class="intermediate">
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
        </div>
    </div>
</div>
vals
  • 61,425
  • 11
  • 89
  • 138
8

What about adding 100% to the container:

.column-parent {
  flex: 1 0 100%;
}

And flex-grow to 1 in the contained element without adjusting the flex basis:

.column-child {
  flex: 1 0 0;
}

Here's how it would look: http://plnkr.co/edit/H25NQxLtbi65oaltNVax?p=preview

E. Serrano
  • 4,634
  • 1
  • 18
  • 15
  • 2
    Ah not quite... There are also an unknown number of child elements. If there are 3, this technique doesn't do what I would like it to: http://plnkr.co/edit/21KD5kuIw3yLKX2NL70l?p=preview . – Michal Charemza Aug 12 '15 at 05:03
  • You're absolutely right. If we cannot know the number of child elements beforehand, this kind of alternatives wouldn't work. – E. Serrano Aug 12 '15 at 15:40