1

I have a row container and three 100% width columns in my layout.

They stack on one another as expected, but when I give a small height to the first of them, I have a behavior I can't explain.

The height doesn't seem to be respected by the next divs.

I would expect the yellow divs to cover the light-blue area that I don't understand why it's there.

enter image description here

* {
  outline: 1px solid red
}

.row {
  background-color: lightblue;
  height: 200px;
  box-sizing: border-box;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-flex: 0;
  -ms-flex: 0 1 auto;
  flex: 0 1 auto;
  -webkit-box-orient: horizontal;
  -webkit-box-direction: normal;
  -ms-flex-direction: row;
  flex-direction: row;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

.col {
  flex-basis: 100%;
  max-width: 100%;
}

.line {
  background-color: blue;
  height: 10px;
}

.second {
  background-color: #EEE8AA;
}
<div class="row">
  <div class="col line">
    
  </div>
  <div class="col second">
    hello
  </div>
  <div class="col second">
    goodbye
  </div>
</div>

Here is a live demo (fiddle).

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Trufa
  • 39,971
  • 43
  • 126
  • 190

3 Answers3

3

An initial setting of a flex container is align-content: stretch. This means that, in a row-direction container, the height of the container will be distributed evenly among the lines.

In your case, you have three flex lines. Each line gets an equal share of the vertical space.

If you switch to align-content: flex-start, you'll pack the lines at the top.

.row {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start; /* NEW */
  background-color: lightblue;
  height: 200px;
  box-sizing: border-box;
}

.col {
  flex-basis: 100%;
  max-width: 100%;
}

.line {
  background-color: blue;
  height: 10px;

}

.second {
  background-color: #EEE8AA;
}

* {
  outline: 1px solid red
}
<div class="row">
  <div class="col line"></div>
  <div class="col second">hello</div>
  <div class="col second">goodbye</div>
</div>

The quick and easy solution would be to use flex-direction: column:

.row {
  display: flex;
  flex-direction: column;
  background-color: lightblue;
  height: 200px;
  box-sizing: border-box;
}

.col {
  flex: 1; /* lines will consume whatever vertical space is available */
  width: 100%;
  max-width: 100%;
}

.line {
  flex: 0 0 10px;
  background-color: blue;
}

.second {
  background-color: #EEE8AA;
}

* {
  outline: 1px solid red
}
<div class="row">
  <div class="col line"></div>
  <div class="col second">hello</div>
  <div class="col second">goodbye</div>
</div>

Learn more about flex alignment along the main axis here:

Learn more about flex alignment along the cross axis here:

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • flexalign-content: flex-start seems to be the winner! thanks a bunch! I'll do some tests but I'm pretty sure it's what I needed. – Trufa Apr 05 '17 at 01:55
  • I need them to be direction row cause they wont always be stacked like this, this is just for the example. thanks! – Trufa Apr 05 '17 at 01:56
  • To see if I understood you correctly, would it be wrong if I do this? https://jsfiddle.net/mLzm2y7y/11/ align-content to start and the make one of the elements 100% because that element happens to have that height? – Trufa Apr 05 '17 at 02:34
  • The `align-content` property distributes free space in the container among flex rows / columns. If you give an item `height: 100%`, that will automatically consume all free space, making `align-content` useless and unnecessary. – Michael Benjamin Apr 05 '17 at 16:56
  • There's nothing wrong with going that route. However, since you have a second item with `height: 10px`, I would adjust the `height: 100%` so both items fit inside the container: https://jsfiddle.net/mLzm2y7y/12/ – Michael Benjamin Apr 05 '17 at 16:59
2

I think what's happening is, since it's a flex row, the height of each flex item is going to be the same - or the space each item will occupy vertically will be the same, even if you've specified a different height for one of the items. So since you've set each of these to flex-basis: 100%, they will occupy the entire height of the parent evenly. The first element is the dark blue area + the light blue area (1/3rd), and the other two are 1/3rd each, too. So the light blue + dark blue is flex-basis: 100% (1/3rd).

It's easier to conceptualize if you replace flex-basis with flex-grow: 1, then you can see the same behavior horizontally https://jsfiddle.net/mLzm2y7y/3/

Michael Coker
  • 52,626
  • 5
  • 64
  • 64
  • 1
    "going to be the same - or the space each item will occupy vertically will be the same" - it should not. https://www.w3.org/TR/css-flexbox-1/#flex-lines "In a multi-line flex container (even one with only a single line), the cross size of each line is the minimum size necessary to contain the flex items on the line" – zerkms Apr 05 '17 at 01:06
  • @Michael if I understand you correctly, the I don't know what's going on here https://jsfiddle.net/mLzm2y7y/5/ Should I understand that once the flex-basis flex-grow is set like this I can't have any dive with set heights or how can I go around this? – Trufa Apr 05 '17 at 01:29
  • @Trufa what's your end goal exactly? How do you want this to behave? If you want the blue child to be 10px tall and the yellow children to occupy the rest of the space, I would do it like this https://jsfiddle.net/mLzm2y7y/6/ – Michael Coker Apr 05 '17 at 01:34
-1

Remove ".line{Height:10px}" your prob will solve.

M. Kumar
  • 19
  • 1