Why does height: 100% on a child element not apply when the parent element has a min-height/max-height value but no height value?

In the first case, you don’t have any height defined so it’s clear that the precentage height on child will fail.

From the specification:

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 (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to ‘auto’.

min-height is only a boundary and the height of your element still depend on its content. If you will have one that exceed 300px the element will have more than 300px

.container {
  background-color: red;
  width: 500px;
  min-height: 300px;
  padding:10px;
}

.child {
  background-color: blue;
  width: 500px;
  height: 400px;
  animation:change 2s linear infinite alternate;
}
@keyframes change{
   from {
     height:100px;
   }
}
<div class="container">
  <div class="child">
    
  </div>
</div>

In the second case you have specified a height so the precentage will work but the height calculation is a bit tricky since we also have min-height

The following algorithm describes how the two properties influence the used value of the ‘height’ property:

  1. The tentative used height is calculated (without ‘min-height’ and ‘max-height’) following the rules under “Calculating heights and margins” above.
  2. If this tentative height is greater than ‘max-height’, the rules above are applied again, but this time using the value of ‘max-height’ as the computed value for ‘height’.
  3. If the resulting height is smaller than ‘min-height’, the rules above are applied again, but this time using the value of ‘min-height’ as the computed value for ‘height’.

In the second case, it’s like you explicitely defined height:300px and percentage will consider this value. In this situation, even if the content is bigger the parent element will not grow and you will have overflow. You can even define a height equal to 0.

.container {
  background-color: red;
  width: 500px;
  min-height: 300px;
  height: 0;
  padding:10px;
}

.child {
  background-color: blue;
  width: 500px;
  height: 400px; 
  animation:change 2s linear infinite alternate;
}
@keyframes change{
   from {
     height:100px;
   }
}
<div class="container">
  <div class="child">
    
  </div>
</div>

Same logic will happen with max-height but in this case the height need to be very big

.container {
  background-color: red;
  width: 500px;
  max-height: 300px;
  height: 99999px;
  padding:10px;
}

.child {
  background-color: blue;
  width: 500px;
  height: 400px; 
  animation:change 2s linear infinite alternate;
}
@keyframes change{
   from {
     height:100px;
   }
}
<div class="container">
  <div class="child">
    
  </div>
</div>

If you are intrested you can transform your logic using flexbox and you will be able to do what you want without having to set an explicit height.

Relying on the default stretch alignment on the cross-axis

.container {
  background-color: red;
  width: 500px;
  min-height: 300px;
  display:flex;
}

.child {
  background-color: blue;
  width: 500px;
  /* height: 100%;*/
}
<div class="container">
  <div class="child">
    
  </div>
</div>

Or using the flex-grow property instead of height in main axis:

.container {
  background-color: red;
  width: 500px;
  min-height: 300px;
  display:flex;
  flex-direction:column;
}

.child {
  background-color: blue;
  width: 500px;
  flex-grow:0.8; /* this is 80%, use 1 for 100% */
}
<div class="container">
  <div class="child">
    
  </div>
</div>

CSS grid can also handle this

.container {
  background-color: red;
  width: 500px;
  min-height: 300px;
  display:grid;
  grid-template-rows:1fr;
}

.child {
  background-color: blue;
  width: 500px;
  height:80%;
}
<div class="container">
  <div class="child">
    
  </div>
</div>

Leave a Comment