5

I've been looking up on the Internet to find out how min-height and height properties work on body and html elements. I've seen the following code at a lot of places

html {
    height: 100%;
}

body {
    min-height: 100%;
}

The above can be used in conjunction with some other divs to get a sticky footer. The other statement being that to set percentage height on body we need to set an explicit height of html as well.

Well Ok, but then what is the height of html tag in percentage relative to? Some answers say it is relative to viewport if the height of viewport is 100%. Now what is this 100% height of viewport relative to?

This post over here says that the height of html element is controlled by the viewport HTML vsBody, but that's not what I saw

Height of HTML Element can Increase

But then why is that when the content increases the height of html element also increases as can be seen on Chrome Developer Tools

Code:

html {
}

.wrapper {
    padding-bottom: 3000px;
}

.footer {
    position: absolute;
    bottom: 0;
    left: 0;
}
<html>
    <head>
        <title>Height</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
        <div class="wrapper">
            <div class="header">
                Header
            </div>
            <div class="content">
                Content
            </div>
            <div class="footer">
                Footer
            </div>
        </div>
    </body>
</html>

Height of HTML element increases

Height of HTML element made fixed

Only when I explicitly set the height of html element to 100% does it get a fixed height:

html {
  height: 100%;
}

.wrapper {
    padding-bottom: 3000px;
}

.footer {
    position: absolute;
    bottom: 0;
    left: 0;
}
<html>
    <head>
        <title>Height</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
        <div class="wrapper">
            <div class="header">
                Header
            </div>
            <div class="content">
                Content
            </div>
            <div class="footer">
                Footer
            </div>
        </div>
    </body>
</html>

And here's the fixed height:

Fixed Height

Sticky Footer

Since the height of HTML Element is taking over the whole content, why can't I achieve a sticky footer by not setting height on html or setting a min-height? Since body is be default position: static, if I position anything, it should be positioned against the html element right?

But none of the below work :/

html {
    min-height: 100%;
}

.wrapper {
    padding-bottom: 1000px;
}

.footer {
    position: absolute;
    bottom: 0;
    left: 0;
}
<html>
    <head>
        <title>Height</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
        <div class="wrapper">
            <div class="header">
                Header
            </div>
            <div class="content">
                Content
            </div>
            <div class="footer">
                Footer
            </div>
        </div>
    </body>
</html>

html {
}

.wrapper {
    padding-bottom: 3000px;
}

.footer {
    position: absolute;
    bottom: 0;
    left: 0;
}
<html>
    <head>
        <title>Height</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
        <div class="wrapper">
            <div class="header">
                Header
            </div>
            <div class="content">
                Content
            </div>
            <div class="footer">
                Footer
            </div>
        </div>
    </body>
</html>
  • In summary can anyone please tell me how is the height of html and body elements calculated?
  • Why doesn't the above sticky footer work?

References:

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Kartik Anand
  • 4,513
  • 5
  • 41
  • 72
  • 1
    if you have separate questions, post them separately!!! – Rachel Gallen Aug 08 '15 at 12:56
  • They're not exactly separate. Both have the same answers I guess, because the sticky footer trick depends upon the heights of body and html element. – Kartik Anand Aug 08 '15 at 12:57
  • In your second code snippet the footer didn't work because you need to set this css .wrapper{position:relative;} this will make sure that footer appears right – Sanjeev Aug 08 '15 at 13:01
  • But I want it to be relative to html element, shouldn't the html element be positioned relative if I am not setting any element under it to be relatively positioned? – Kartik Anand Aug 08 '15 at 13:03
  • because you parent element i.e., wrapper is not set to position:relative , the default setting to any div is static so your parent element i.e, wrapper has css position:static so when you tried to position your footer absolute it was unable to find a parent whose position it can use as a relative – Sanjeev Aug 08 '15 at 13:11
  • So why did it position it relative to viewport? Why not the root element Html ? – Kartik Anand Aug 08 '15 at 13:13
  • same reason becuase html tag default position is also 'static' just change it like this html{ position:relative;} and it will work – Sanjeev Aug 08 '15 at 13:24
  • @L-X Yes, setting position to relative works, but then why don't people go with this. Isn't this simpler than setting heights and min-heights on body, html, and div elements? – Kartik Anand Aug 08 '15 at 13:28
  • I have updated my answer check out and default is static which means flow linearly (I guess ) means content will be positioned when after other which is more natural I guess – Sanjeev Aug 08 '15 at 13:32
  • Most important: Disregard what it says in the phrogz.net article. It was probably a true description of what IE did, when the article was written in 2004, but it's not what modern browsers do. – Alohci Aug 08 '15 at 14:39

3 Answers3

6

The concept you are missing is called the "Initial Containing Block".

The html element (by definition) and the body element (by default) are block elements, and behave the same way as all block level elements. So you can set a fixed height, let it be as tall as its content, or give it a percentage height (and/or max and min variants). When a block level element is given a percentage height, that is a percentage height of its "Containing Block". For this to work, the Containing Block's height must not depend (even potentially) on the height of its content, because that would cause a circular dependency.

For most elements, their containing block is the one formed by their parent element, but there are exceptions. In particular, are the two examples of your question, the footer which is position:absolute and the root element of the document which obviously doesn't have a parent element, in your case, the <html> element.

As explained by L-X, for absolute positioned elements, their containing block is formed by their nearest non-statically positioned ancestor element. If no such one exists, as in your case, the containing block used is the "Initial Containing Block".

The root (<html>) element's containing block is also the "Initial Containing Block".

So what is the "Initial Containing Block"? It's a rectangle that has the height and width of the viewport, but is anchored at the origin of the canvas (0, 0). This is different to the viewport, which has the same dimensions, but is not anchored, the scroll bars allow the viewport to move over the canvas.

Now we can answer your questions, with respect to your last snippet

how is the height of html and body elements calculated?

The html element there is the height of its contents - the header and content elements plus the wrapper's padding. (the footer isn't counted - its position:absolute takes it out of the flow. If it was height:100% it would be the height of the Initial Containing Block, which is the height of the viewport.

Why doesn't the above sticky footer work?

The footer is positioned relative to the Initial Containing Block - (0, 0) plus the height of the Initial Containing Block, less its own height. But the scrollbars allowing the viewport to range over the canvas, down to the bottom of the html element. It's not locked at (0, 0) so the footer moves relative to it - i.e. it is not sticky to the viewport, and it is not positioned at the bottom of the <html> element.

Alohci
  • 78,296
  • 16
  • 112
  • 156
  • Any idea why it's different in an iframe? [For example](http://greggman.com/downloads/examples/body-min-height-100-percent.html) here's a page where everything expands to fill the page. But put it in an iframe and it fails to fill the iframe. Any idea why? – gman May 05 '16 at 09:28
  • @gman - Note that the rendering is the same if you omit `height:100%`. Either way, the canvas element's height expands to maintain it's aspect ratio. i.e. Your test is invalid. – Alohci May 05 '16 at 09:53
  • Thanks for pointing that out. Any idea why is it not respecting 100% height? – gman May 06 '16 at 07:10
  • @gman - because the container's height depends on its content. So respecting percentage heights would create a circular dependency. – Alohci May 06 '16 at 08:38
1

According to the CSS specification:

When a percentage value is set for a property of the root element and the percentage is defined as referring to the inherited value of some property, the resultant value is the percentage times the initial value of that property.

Deryck
  • 7,608
  • 2
  • 24
  • 43
1

Updated

Ok your problem is why didn't the footer position itself to html tag , insted it position itself relative to viewport ? right!

Because every html element default positioning is static and when you defined your footer to be positioned absolute it couldn't find a PARENT div or html element whose position attribute was relative enter image description here

.html{
    position:relative;
}

So you have two option either make html position to be relative or wrapper div position to be relative

Sanjeev
  • 4,255
  • 3
  • 28
  • 37
  • I don't want an always visible footer. I'm looking for the one that sticks at the bottom. I know how to do it, just confused why the above doesn't work? – Kartik Anand Aug 08 '15 at 13:10
  • Checkout the computed section in chrome developer tools and go below where position is defined for your wrapper div , – Sanjeev Aug 08 '15 at 13:21