1

I am observing following behavior.

This code:

<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
      <div container style={{ flex: 1, border: "2px solid green" }} />
      <div style={{ minHeight: 300, border: "1px solid blue" }}>
        <div id="map" style={{ border: "3px solid red", height: "100%" }} />
      </div>
</div>

results in this:

enter image description here

See red border, it seems div with id map took some height.

Now if I make single change to above code, and change height of top div to minHeight:

<div
      style={{ minHeight: "100%", display: "flex", flexDirection: "column" }}
    >
      <div container style={{ flex: 1, border: "2px solid green" }} />
      <div style={{ minHeight: 300, border: "1px solid blue" }}>
        <div id="map" style={{ border: "3px solid red", height: "100%" }} />
      </div>
</div>

You can see the screen shot below, red border, the map has no height anymore.

enter image description here

Seems strange why playing with the top div affects the div with id map in such way... isn't it?

demo

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • as you said it's strange .. the height:100% in the red element should not work in both cases and you should always get the last screenshot because there is no height defined in its parent element – Temani Afif Jun 21 '19 at 09:32
  • @TemaniAfif Yes, if I correctly understood this answer: https://stackoverflow.com/a/8468131/3963067, since the parent of `map div` has minHeight, map div should not be able to take height, in both cases... but strangely in first it does – Giorgi Moniava Jun 21 '19 at 09:34
  • it has to do with flexbox. In some particular cases percentage height works when there is no cylic dependency which means that sometimes the browser is able to resolve the percentage value even without height explicitely defined (ex: https://stackoverflow.com/a/54271377/8620333 (check the end of the answer) – Temani Afif Jun 21 '19 at 09:38

1 Answers1

2

From the specification

Sometimes the size of a percentage-sized box’s containing block depends on the intrinsic size contribution of the box itself, creating a cyclic dependency. When calculating the intrinsic size contribution of such a box (including any calculations for a content-based automatic minimum size), a cyclic percentage ...

Then a whole set of complex rules and:

Then, unless otherwise specified, when calculating the used sizes and positions of the containing block’s contents:

  1. If the cyclic dependency was introduced due to a block-size or max-block-size on the containing block that causes it to depend on the size of its contents, the box’s percentage is not resolved and instead behaves as auto.

  2. Otherwise, the percentage is resolved against the containing block’s size. (The containing block’s size is not re-resolved based on the resulting size of the box; the contents might thus overflow or underflow the containing block).

Basically we need to see if the percentage can be resolved without any cyclic denpendeny or not.

In the second case, you defined the container to have a min-height which means that its height will be defined by its content so we need to first know the content height to find the height of the container and this will make the percetange height fail to auto because we cannot resolve it since we only have min-height:300px and we need to also find the height based on the content.

In the first case, you defined the container to have height:100% so the height is defined but we still have only min-height in the child element. Here it's a bit complex because the height of that element can be found using the flex properties. Basically the browser can resolve the height of that element without knowing its content then use the calculated height to resolve the percentage value.

Here is a basic example to better illustrate:

.box {
  display: flex;
  flex-direction: column;
  border:1px solid red;
  margin:10px;
}

.box>div {
  border: 1px solid;
}

.height {
  height: 80%;
  background: red;
}
<div class="box" style="min-height:200px;">
  <div style="min-height:100px;">
    <div class="height">content here</div>
  </div>
</div>

<div class="box" style="height:200px;">
  <div style="min-height:100px;">
    <div class="height"> content here</div>
  </div>
</div>

<div class="box" style="height:200px;">
  <div style="flex-basis:50%;">
    <div class="height"> content here</div>
  </div>
</div>

<div class="box" style="height:200px;">
  <div style="flex-grow:1;">
    <div class="height"> content here</div>
  </div>
</div>

You can see that in all the cases where the height of the flex container is defined we are able to resolve the percentage height of the nested element because the browser is able to calculate the height without the need of the content.

In reality, the content is also used to define the height which add more complexity. Let's consider the below example:

.box {
  display: flex;
  flex-direction: column;
  border: 1px solid red;
  margin: 10px;
}

.box>div {
  border: 1px solid;
}

.height {
  height: 80%;
  background: red;
}
<div class="box" style="height:200px;">
  <div style="flex-basis:50%;">
    <div class="height">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse pulvinar nunc sit amet justo congue, et convallis diam porttitor. Curabitur semper tellus eget semper vehicula. In auctor ut nunc vitae faucibus. Integer molestie aliquam lacinia.
      Vestibulum blandit sem vitae tortor fermentum auctor. Morbi pharetra ante laoreet vestibulum laoreet. Nam id tempor eros, non ultrices leo. Quisque tincidunt hendrerit tortor ut malesuada.
       Vestibulum blandit sem vitae tortor fermentum auctor. Morbi pharetra ante laoreet vestibulum laoreet. Nam id tempor eros, non ultrices leo. Quisque tincidunt hendrerit tortor ut malesuada.</div>
  </div>
</div>

You can see that the text is overflowing the red div (its container) and the height of the flex item is matching the height of the text. In this case, the browser is still able to identify the height of the flex item based on the flex properties and those properties also consider the content!

A flex item cannot shrink past its content size that's why flex-basis:50% is not giving 50% of the parent height but the min value between 50% and the content height.

If you add min-height:0 you will have a different behavior:

.box {
  display: flex;
  flex-direction: column;
  border: 1px solid red;
  margin: 10px;
}

.box>div {
  border: 1px solid;
}

.height {
  height: 80%;
  background: red;
}
<div class="box" style="height:200px;">
  <div style="flex-basis:50%;min-height:0">
    <div class="height">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse pulvinar nunc sit amet justo congue, et convallis diam porttitor. Curabitur semper tellus eget semper vehicula. In auctor ut nunc vitae faucibus. Integer molestie aliquam lacinia.
      Vestibulum blandit sem vitae tortor fermentum auctor. Morbi pharetra ante laoreet vestibulum laoreet. Nam id tempor eros, non ultrices leo. Quisque tincidunt hendrerit tortor ut malesuada.
       Vestibulum blandit sem vitae tortor fermentum auctor. Morbi pharetra ante laoreet vestibulum laoreet. Nam id tempor eros, non ultrices leo. Quisque tincidunt hendrerit tortor ut malesuada.</div>
  </div>
</div>

Now the flex item is taking 50%of the parent height (ignoring its content) then its child element is taking 80% of that height and the content is logically overflowing.


TL;DR

A flex item (when the flex direction is column and the flex container have an explicit height) will have its height defined by the flex properties and considering the content inside (basically the content will only set the min-height constraint) then after calculating that height the browser can resolve any percentage value of height for the items inside.


Here is a related question where we have a similar issue and where we are able to resolve the percentage value: Why is my Grid element's height not being calculated correctly?

Community
  • 1
  • 1
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Dear Temani, you say *"Here it's a bit complex because the height of that element can be found using the flex properties. Basically the browser can resolve the height of that element without knowing its content "* - can you elaborate how that height can be found using the flex properties? What would the height be in that case and why? – Giorgi Moniava Jan 17 '21 at 18:15
  • @gmoniava it's the flex-basis/flex-shrink/flex-grow that define the final height of a flex item. The browser will use them and will consider the content to define the final height. The content is not only the one defining the height like a non-flex item. That's why percentage height can be resolved inside because it will use a height computed using flex properties and not a height:auto even if that computed height depend on the content which is the tricky part here. – Temani Afif Jan 17 '21 at 19:01
  • I am finding a bit hard to follow, so in the first case, what will be the computed height of the inner div (the one with min height)? 300? – Giorgi Moniava Jan 17 '21 at 20:04
  • Even in your examples, in the first three cases, the computed height of the black rectangle is 100, but still in the first case, it can't take the height of the div with class "height". – Giorgi Moniava Jan 17 '21 at 20:38
  • @gmoniava in your first case, the parent has a height:100% so its height is explicit and it doesn't depend on its content (Until now it's OK). inside that parent two flex items, one with flex:1 so it's computed height will be the remaining height inside the parent and the other with flex:auto( since you didn't set it) so flex-grow:0 flex-shrink:1 and flex-basis:auto AND you have defined a min-height:300px so considering all this the flex item will have a computed *final* height equal to 300px and this is our reference for the element inside it having height:100% – Temani Afif Jan 17 '21 at 20:48
  • @gmoniava in your second case AND my first case, the difference is that the parent doesn't have an explicit height and this make things more complex. In such case the browser will not able to do the same calculation because even the height of the container may increase since we only defined a min-height which mean that the height depend on the content so in this case the browser cannot handle this and everything will fall to auto and the percentage height inside will not resolve. – Temani Afif Jan 17 '21 at 20:51
  • @gmoniava in all the cases we will have a computed height but what I am trying to explain is that in some cases such height can be used as reference for percentage and in other case it cannot because it was computed using the content ... I know it sounds a bit complex and honestly you are facing some special complex edge cases of CSS that are not easy to understand. – Temani Afif Jan 17 '21 at 20:53
  • Thanks. Ok, I think I have more or less understood this. The only part on which I am not fully clear now is why in *your first case* despite the computed height being 100, the inner div with class "height" can't resolve the percentage... – Giorgi Moniava Jan 18 '21 at 07:05
  • @gmoniava the issue is not with having a computed height or not. Every element will have a computed height at the end. The issue is within the algorithm that calculate the height. In some cases, the browser is able to *easily* resolve a percentage height and in other cases they will fail to auto because the algorithm is complex and may end having undefined behaviors – Temani Afif Jan 18 '21 at 07:39
  • OK, thanks for your explanation. At least I have rough idea what was going on now. – Giorgi Moniava Jan 18 '21 at 07:58