I'd like to understand why the green div with cyan border behaves like so in these cases.
.wrapper {
display: flex;
border: solid 2px black;
}
.red {
width: 25px;
height: 25px;
background-color: red;
}
.green {
height: 100%;
background-color: green;
border: solid 2px cyan;
}
.blue {
width: 50px;
height: 50px;
background-color: blue;
}
<div class="wrapper">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
Result: Green div has zero height instead of blue's height.
.wrapper {
display: flex;
border: solid 2px black;
}
.red {
width: 25px;
height: 25px;
background-color: red;
}
.green {
height: 100%;
background-color: green;
border: solid 2px cyan;
}
.blue {
width: 50px;
height: 50px;
background-color: blue;
}
<div class="wrapper">
<div class="wrapper">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
</div>
Result: The green div has blue's height, as expected.
.wrapper {
display: flex;
border: solid 2px black;
}
.red {
width: 25px;
height: 25px;
background-color: red;
}
.green {
height: 100%;
background-color: green;
border: solid 2px cyan;
}
.blue {
width: 50px;
height: 50px;
background-color: blue;
}
<div class="wrapper">
<div>
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
</div>
Result: The green div has blue + red + (cyan border * 2) height, as expected.
Why do I have to add a wrapper with display flex to make the height percentage work the way I expect it to work?
Doing some tinkering I discovered something. In the first example, removing height: 100%
(or setting it to auto) makes it grow. Why is it that when the green div has height auto it takes all the height of the parent (minus its own border) but not when it is set as 100%?
.wrapper {
display: flex;
border: solid 2px black;
}
.red {
width: 25px;
height: 25px;
background-color: red;
}
.green {
height: auto;
background-color: green;
border: solid 2px cyan;
}
.blue {
width: 50px;
height: 50px;
background-color: blue;
}
<div class="wrapper">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
The green div with height: '100%'
is set to be the same height with its containing block, which is the parent div with display: 'flex'
. However, the height of the parent div is indefinite, so that height: '100%'
will behave like height: 'auto'
. And there is no content in the green div, so that it will has zero height.
W3C CSS standards: height - percentage
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 (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
W3C CSS standards: containing block
W3C CSS standards: definite & indefinite size
The green div's containing block is still its parent div with display: 'flex'
, also the extra wrapper. Here is a difference, the wrapper has a parent with display: 'flex'
, which means the wrapper is a flex item now. According to flex layout algorithm, size of the wrapper will be considered definite. Now 100% will be effective, make the green div has the same height with the wrapper.
Discard some details, the layout procedure is like this:
25px
.height: '100%'
, but its containing block's height is indefinite now, so that treat as height: 'auto'
, which gives content height 0 + border * 2. Green has height 4px
.50px
.50px
.50px
.50px
. Then the heights of its children are set to be 50px
and definite.25px
and 50px
.50px
. The total height will be added border * 2, 54px
.W3C CSS standards: flex layout algorithm - Definite Sizes
Once the cross size of a flex line has been determined, items in auto-sized flex containers are also considered definite for the purpose of layout; see step 11.
W3C CSS standards: flex layout algorithm - Cross Size Determination
If the flex item has align-self: stretch, redo layout for its contents, treating this used size as its definite cross size so that percentage-sized children can be resolved.
The procedure is similar to the second example. The differences are bold and italic.
25px
.height: '100%'
, but its containing block's height is indefinite now, so that treat as height: 'auto'
, which gives content height 0 + border * 2. Green has height 4px
.50px
.79px
.79px
.79px
. Then the heights of its children are set to be 79px
and definite.25px
and 50px
.79px
. The total height will be added border * 2, 83px
.box-sizing: 'border-box'
to avoid bother of adding border line width.height
from the green of the first example. Flex layout has align-items: stretch
by default, which will stretch the green's height to align the highest one in its cross line. Otherwise explicit height will override the stretch.