Extra top padding in a container when using HTML5 doctype

There is extra top padding in the following div:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Extra Top Padding</title>
    <style>
        div {
            background: tan;
        }
        div * {
            vertical-align: middle;
        }
        span {
            font-size: 16px;
        }
    </style>
</head>

<body>
    <div id="container">
        <img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span>
    </div>
    <p id="indicator"></p>
    <script>
        document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
    </script>
</body>

</html>

DEMO

It shows correctly if you use HTML 4.01 Transitional doctype:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

Is it a bug in HTML5?

If you replace


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 [color=red]Transitional[/color]//EN" "http://www.w3.org/TR/html4/[color=red]loose[/color].dtd">

with


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/[color=blue]strict[/color].dtd">

you will see the same behavior as you see with


<!DOCTYPE html>

The problem is the way inline objects are treated in the Transitional (loose) and older doctypes.
If treated correctly, inline objects should have a margin on two sides (not padding) just like you see around words in a sentence. The transitional (older) doctypes do not correctly apply that margin.
After upgrading the DOCTYPE to 4.01 strict or 5, change {vertical-align:middle;} to {vertical-align:top;} and the “undesired” margin will go away.

If you wish to zap the vertical margins entirely, you can add {line-height:0} to div#container and restore a line-height in div *.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Rain Lover: Extra Top Padding</title>
    <style>
#container {
    background:tan;
    line-height:0;
}
div * {
    display-:inline-block;
    vertical-align:middle;
    line-height:1;
}
span {
    font-size:16px;
}
    </style>
</head>
<body>

<div id="container">
    <img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span>
</div>
<p id="indicator"></p>
<script>
document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
</script>

</body>
</html>

My editing time elapsed. Please delete the disabled line from the previous code:


div * {
   [color=red]display-:inline-block;[/color]
    vertical-align:middle;
    line-height:1;
}

By container padding I mean extra space inside the container although the elements padding is 0 when you inspect them. If it is margin on two sides, then the content alignment should be in the middle. Besides, I should be able to remove it by something like:

* {margin:0; padding:0;}

After upgrading the DOCTYPE to 4.01 strict or 5, change {vertical-align:middle;} to {vertical-align:top;} and the “undesired” margin will go away.

It’s not the right way to align the div content in the middle of the container.

You are correct. But that is not how I read your question. And just in case I misunderstood, I posted that last bit of code in post #2 which middle aligns everything.

Your example is slightly off middle because it is inheriting the default browser font characteristics. My last example sets the inherited line-height to zero, then expands it for your content.

Try this experiment:
Add margin and padding to the span selector…


span {
    font-size:16px;
    margin:16px;
    padding:16px;
}


You will see horizontal padding and margin applied to the text, but NO vertical padding and margin is apparent.

Then set div * to {display:inline-block}:


div * {
    display:inline-block;
    vertical-align:middle;
    line-height:1;
}


Suddenly the vertical padding and margins are applied.

As you said the problem seems to be the line-height difference in strict and loose mode. But display:inline-block seems to have no effect and to restore div * line-height to default you should use normal:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Extra Top Padding</title>
    <style>
        div {
            background: tan; line-height:0;
        }
        div * {
            vertical-align: middle; line-height:normal;
        }
        span {
            font-size: 16px;
        }
    </style>
</head>

<body>
    <div id="container">
        <img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span>
    </div>
    <p id="indicator"></p>
    <script>
        document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
    </script>
</body>

</html>

Hi,

As Ron said the difference is between strict doctypes (which the html5 doctype is) and the transitional doctype you used. There are many legacy behaviours in transtitonal documents so the differences will be many.

The problem you are experiencing was documented about 12 years ago by Eric meyer here.

The solution to your problem is as Ron said to set the line-height and to set vertical-align:top. As the line-height is the same for both the span and the image then vertical-align:middle makes no sense because they are the same size.

This renders exactly the same in both doctypes.


<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extra Top Padding</title>
<style>
* {
	margin:0;
	padding:0;
	line-height:16px
}
div { background: tan; }
div * { vertical-align:top; }
span { font-size: 16px; }
</style>
</head>

<body>
<div id="container"><img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span></div>
<p id="indicator"></p>
<script>
document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
</script>
<div><a href="https://developer.mozilla.org/en-US/docs/Images%2C_Tables%2C_and_Mysterious_Gaps">Images and mysterious gaps</a></div>
</body>
</html>


Even if you reduce the size of the span it will still be aligned centrally because the line-height is still 16px.


<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extra Top Padding</title>
<style>
* {
	margin:0;
	padding:0;
	line-height:16px
}
div { background: tan; }
div * { vertical-align:top; }
span { font-size: 10px;vertical-align:top}
</style>
</head>

<body>
<div id="container"><img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span></div>
<p id="indicator"></p>
<script>
document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
</script>
<div><a href="https://developer.mozilla.org/en-US/docs/Images%2C_Tables%2C_and_Mysterious_Gaps">Images and mysterious gaps</a></div>
</body>
</html>

It’s just one of those things that you need to know and vertical-align:middle behaves differently between standards amosd, almost standards mode and quirks mode but most times you can work around the problem quite easily.

Thanks for the explanations and educational reference! :slight_smile:

Actually the div size needs to be larger than the font size, i.e. 20px, not 16px. If the text includes letters like gjy, then it overflows the container:

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extra Top Padding</title>
<style>
* {
	margin:0;
	padding:0;
	line-height:128px
}
div { background: tan; }
div * { vertical-align:top; }
span { font-size: 128px; }
</style>
</head>

<body>
<div id="container"><img src="https://ssl.gstatic.com/images/icons/gplus-128.png"><span>gjy</span></div>
<p id="indicator"></p>
<script>
document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
</script>
</body>
</html>

Even if you reduce the size of the span it will still be aligned centrally because the line-height is still 16px.

What if I increase the font size:

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extra Top Padding</title>
<style>
* {
	margin:0;
	padding:0;
	line-height:128px
}
div { background: tan; }
div * { vertical-align:top; }
span { font-size: 128px; }
</style>
</head>

<body>
<div id="container"><img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span></div>
<p id="indicator"></p>
<script>
document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
</script>
</body>
</html>

In my humble opinion, we are seeing the line-height of the div in strict mode. If we get rid of the container line-height, the container height will be exactly equal to the content height, as expected. I just add font-size:0; to the code in my question:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Extra Top Padding</title>
    <style>
        div {
            background: tan; font-size:0;
        }
        div * {
            vertical-align: middle;
        }
        span {
            font-size: 16px;
        }
    </style>
</head>

<body>
    <div id="container">
        <img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text</span>
    </div>
    <p id="indicator"></p>
    <script>
        document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
    </script>
</body>

</html>

DEMO

It reduces the height of the strut so that it fits entirely within the 20px height of the text and works with any font or image size.

Yes the inline box model is a thing of beauty as Eric Meyer shows in his inline box model article. :slight_smile:

You have to remember that the font-size of an element is not the same as the line-height and for large fonts you get half leading and content areas added to the font so in fact your 128px font will need about 150px of space to render correctly so a smaller line-height will show it cut off or misplaced. It does make alignment difficult to achieve in some cases. Also note that fonts have descenders and ascenders of varying height which differs between browsers and fonts then pixel precision will be difficult to achieve.

In your first large font example then both strict and loose show the same display anyway.

The font-size:0 is a known hack to cure the white space gaps on elements (especially inline-block) but does kill inheritance so is only useful in limited situations.

In your last example I think you should address the line-height instead of the font-size which seems to scale well without any gaps.


<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extra Top Padding</title>
<style>
div {
	background: tan;
	line-height:0
}
div * { vertical-align: middle; }
span {
	font-size: 16px;
	line-height:normal
}
</style>
</head>

<body>
<div id="container"> <img src="https://ssl.gstatic.com/images/icons/gplus-16.png"><span>Some text ghj</span> </div>
<p id="indicator"></p>
<script>
document.getElementById('indicator').textContent = document.getElementById('container').clientHeight;
</script>
</body>
</html>

That scales all the way up and down nicely for me and without the font-size complications.