Height Calculation by Browsers:Containing Blocks and Children

Height Calculation By Browsers : Containing Blocks and Children

The height CSS property on MDN:

Percentages

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.
A percentage height on the root element is relative
to the initial containing block.

In 1., the height attribute of the parent isn't explicitly specified, therefore the value computes to auto.

In 2., the height attribute is specified and therefore it's calculated with respect to the parent

Heights rendering differently in Chrome and Firefox

So first you have the W3C standards, which are a set of guidelines for browser makers.

And then you have the browser makers, who are free to do whatever they want (as evidenced by a history of deviations by Internet Explorer).

In particular, with CSS percentage heights, there are clear differences in behavior among browsers.

You've posted one example. Here's another:

Percentage Heights in Flexbox: Chrome/Safari vs Firefox/IE

When working with flexbox, Chrome and Safari resolve percentage heights on flex items based on the value of the parent's height property. Firefox and IE11/Edge prioritize the parent's flex height.

It appears Webkit browsers adhere to a more traditional interpretation of the spec:

CSS height property

percentage
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 and this element is not absolutely positioned, the value computes to "auto".

auto
The height depends on the values of other properties.

In other words, for percentage height to work on an in-flow child, the parent must have a set height.

That is the traditional interpretation of the spec: The term "height" means the value of the height property. My own view is that this language is vague and open to interpretation, but the height property requirement has become the predominant implementation. I've never seen min-height or max-height work on a parent when dealing with percentage values.

Recently, however, Firefox and IE have broadened their interpretation to accept flex heights, as well.

Examples of Firefox and IE using a parent's flex height as reference for a child's percentage height:

  • Chrome ignoring flex-basis in column layout
  • Chrome / Safari not filling 100% height of flex parent
  • Height is not correct in flexbox items in Chrome
  • Flexbox in Chrome--How to limit size of nested elements?

Knowing which browsers are in compliance with the spec is a bit difficult because, as I mentioned before, the spec language seems vague and open to interpretation.

With the last update to this part of the definition being in 1998 (CSS2), and the advent of new forms of height such as flex height, an update seems long overdue.

I think it's fair to say that when it comes to percentage heights, until the spec definition gets an update, you can expect rendering differences among browsers.


Alternative Solutions

Here are two alternatives to consider when wanting a child element to take the parent's full height.

  1. Apply display: flex to the parent. This automatically sets align-items: stretch, which tells the child to expand the full available height of the parent.

  2. Apply position: relative on the parent and position: absolute; height: 100%; width: 100% on the child. With absolute positioning, a percentage height will work without a specified height on the parent.

Responsive cross browser solution for equal height columns with children

If crossbrowser but not for dinosaurs thne inline-block and a pinch of calc() might help:

* {  box-sizing: border-box;  margin:0;}.parent div div a,.parent div  div {  border: solid 1px;}.parent div.left {  padding: 1em;  border: solid 1px;}.parent div {  display: inline-block;  vertical-align: top;  width: 100%;}.parent {  width: 70%;/* demo purpose, do run it in full page too */  margin: auto;  background:yellow;}img {  width: 100%;  display: block;}.parent .left {  width: 75%;}.parent .right {  width: 25%;}.parent div div a {  margin: 0.88em;  display: block;  text-align: center;  /* if floatting pseudo do  overflow:hidden;*/}.parent div div a:before {  content: '';  padding-top: calc(60% - 0.5em);/* is calc() allowed ?  if not keep 60% and remove margin:1em from links */  /* float:left; or with vertical-align */  display: inline-block;  vertical-align: middle;}
<div class="parent">  <div class="left">    <div class="image-container">      <img class="image" src="http://placehold.it/1300x780" alt="Sample Image" />    </div>  </div><!-- cure white-space disturbance  --><div class="right">    <div class="cta">      <a>LINK #1</a>    </div>    <div class="cta">      <a>LINK #2</a>    </div>    <div class="cta">      <a>LINK #3</a>    </div>  </div></div>

CSS: What is the defined behaviour for parent height:auto and children height:100%?

You've not given the HTML a DOCTYPE, so the normal CSS rules are modified by the page being rendered in quirks mode.

This effect you see is described in the Quirks Mode Living Standard

3.5. The percentage height calculation quirk

In quirks mode, for the purpose of calculating the height of an
element element, if the computed value of the position property of
element is relative or static, the specified value for the height
property of element is a <percentage>, and element does not have a
computed value of the display property that is table-row,
table-row-group, table-header-group, table-footer-group, table-cell or
table-caption, the containing block of element must be calculated
using the following algorithm, aborting on the first step that returns
a value:

  1. Let element be the nearest ancestor containing block of element, if
    there is one. Otherwise, return the initial containing block.

  2. If element has a computed value of the display property that is
    table-cell, then return a UA-defined value.

  3. If element has a computed value of the height property that is not
    auto, then return element.

  4. If element has a computed value of the position property that is
    absolute, or if element is a not a block container or a table
    wrapper box, then return element.

  5. Jump to the first step.

Following this algorithm through, and taking into account the quirks rules 3.6. The html element fills the viewport quirk and 3.7. The body element fills the html element quirk you'll see that the 100% height of the .box elements is 100% of the computed height of the body element, which is 100% of the height viewport less the default margins that the body element has.

Codepen automatically adds the DOCTYPE to your mark-up, so the above quirks mode rules do not apply. Instead, the height of the .box elements is determined by the normal CSS rules for percentage heights, which states that in your case "the used height is calculated as if 'auto' was specified", and then 10.6.3 Block-level non-replaced elements in normal flow when 'overflow' computes to 'visible' which says the height is the height of the element's content.

How Exactly Is The Containing Block Determined

First, the containing block in both cases is the same for inner and it's outer. overflow play no role here, same for the usage of flexbox. More detail: https://www.w3.org/TR/CSS2/visudet.html#containing-block-details

Now, you need to understand the trickery around percentage height. The general rule is: "the containing block need to have an explicit height"

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'. ref

Considering this, you can assume that your percentage height will fail in both cases BUT things have changed and now we can resolve percentage height in some particular cases where we don't have any explicit height defined on the containing block.

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 percentage value that resolves against a size in the same axis as the intrinsic size contribution (a cyclic percentage size) is resolved specially: ref

If you keep reading, you will find a lot of complex concept and definition not easy to understand. I will not detail all of them but your second case is one of them.

To make it easy: Flexbox force some sizes to be definite allowing percentage height to be resolved (https://drafts.csswg.org/css-flexbox-1/#definite-sizes).

There are more cases like that related to flexbox and CSS grid as well:

Percentage 'min-height' works only when element has indirect parent with 'display: flex'

Why does `height: 100%` value 'work' for child tags of grid-items?

https://stackoverflow.com/a/52137966/8620333

Webbrowser height calculation top margin falsely taken into account?

Finally having a bit of time and inspired by the reply of davidgnin I sought deeper and did a dive into the W3C boxmodel definitions. This definitely answers my question on terms of Is this a bug? and Is this intended? and the answers are: NO and YES

You'll find the reason explained here, where it clearly states the following:

The top margin of an in-flow block element collapses with its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance.

The reason as to why this is done is a bit unclear to me (so I welcome anyone who can explain the reasoning behind this) thus I am unable to answer my question of To what purpose?

Luckily knowing why this occurs also enables us to counter the effect:

  1. Establish a new block formatting context by for example using overflow:hidden
  2. Separating the parent and child by a padding, border, inline element or clearance

I hope that this may help someone ending up in the same situation.

Percentage Height HTML 5/CSS

I am trying to set a div to a certain percentage height in CSS

Percentage of what?

To set a percentage height, its parent element(*) must have an explicit height. This is fairly self-evident, in that if you leave height as auto, the block will take the height of its content... but if the content itself has a height expressed in terms of percentage of the parent you've made yourself a little Catch 22. The browser gives up and just uses the content height.

So the parent of the div must have an explicit height property. Whilst that height can also be a percentage if you want, that just moves the problem up to the next level.

If you want to make the div height a percentage of the viewport height, every ancestor of the div, including <html> and <body>, have to have height: 100%, so there is a chain of explicit percentage heights down to the div.

(*: or, if the div is positioned, the ‘containing block’, which is the nearest ancestor to also be positioned.)

Alternatively, all modern browsers and IE>=9 support new CSS units relative to viewport height (vh) and viewport width (vw):

div {
height:100vh;
}

See here for more info.

Child's `height: 100%;` is not taking parent's full height, why?

Looks like I misunderstood the term containing block, I thought it would be the parent, but not really, there's much more into this.

I had to dig into the W3C standard to find out:

Definition of "containing block"

The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element.

The containing block in which the root element lives is a rectangle called the initial containing block.

For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest block container ancestor box.

...



Related Topics



Leave a reply



Submit