I have a div C which
D2 - very long content
The reason why things do not work the way you expect is simply because
max-height does not set the height of the containing div. All it does is, as its name implies, set a maximum limit to the height of the div.
Here's a quote from the W3 CSS2 specification on how the percentage heights are calculated on block elements. This might help to shed some light on the matter:
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'.
In your case the height of the containing div is not set explicitly and depends on content height, because when you set the
max-height of the containing div to
90%, and there is not enough content to stretch the containing div to
90% of the height of its own containing element, the height of the containing div will be less than 90% of the height of its own containing element.
The browser renders the containing div with an initial height of
auto, which computes to
0px as there is no content yet. Along comes the contained div which wants to be rendered with a height of
100% of the height of its containing block, the browser realizes that this is ridiculous, as
0px is exactly
0px again. So it decides to set the height of the contained div to
auto instead. If it didn't do so, then the contained div would never be visible, because no matter what happens next,
100% of the containing block's height of
0px is always going to be
0px. Remember that the browser is trying to stick to this part of the rule quoted above:
The percentage is calculated with respect to the height of the generated box's containing block
ONLY NOW along come some more div's which would like to be rendered inside the contained div. At the moment when the previous decisions were made, the browser didn't yet know about these div's, they're a bit late to the party. If the browser was then to backtrack and fix itself up after it had rendered those div's, it would effectively be breaking the part of the rule quoted above. As it would indirectly* be setting the percentage height of the contained div based on the height of its contents.
Because of this the W3 specification people have come up with the second part of the rule. Which lets the browser decide to set the height of the contained div to
auto if the height of its containing div is not set (and therefore defaults to
So you could say that those late div's are lucky that the browser has taken some precautions and is still able to render those div's, as it has been preemptive and has set the height of the contained div to
auto to accommodate for latecomers.
*by calculating the height of the containing div based on the height of the contents of the contained div, and then basing the percentage height of the contained div on this value.
Browsers are just sticking to the W3 specification, which is a good thing. Your first fiddle works because the browser makers are adhering to the specification, and your second fiddle doesn't work for the exact same reason.
You can only fix your issue by making sure that the div which you want to have a height of
90% of the browser window is a direct descendant of a div which has its height set to
100% of the browser window. If the ancestor div is not absolutely placed, every ancestor of the div, all the way up to the
html document element, would also have to have a height of
100% set on itself.
The line above is true, except if an ancestor is encountered which is absolutely placed (which would take it out of the regular document flow), without this ancestor itself having an ancestor with
position: relative set (which would force its absolute positioning to be based on the position of its relatively positioned parent instead of on the height of the browser window), and this ancestor is set to be the height of the browser window (using
top: 0px; bottom: 0px;). In that case the running up the DOM tree will stop at the absolutely positioned ancestor.