HTML5 does NOT allow “self-closing” tags …
… on non-void elements, at least.
One of the big misconceptions about HTML5 is that any tag can be self-closed. That’s not true, though it appears that way.
What HTML5 does is provide parsing rules for handling mismatched tags and markup. While it seems like self-closing tags are acceptable, that’s not the case. This post explains what’s really at play. Let’s take a look.
‘Self-closing’? Our old friend />
Let’s separate void elements from empty tags that don’t contain content. You’re probably familiar with "void" elements — elements that can’t have any content. They include the img, br, hr, and meta elements.
In XHTML, we closed void elements according to the rules of XML syntax, which requires all elements to be closed with end tags or self-closing tags. That’s where we get the familiar space-slash ( />) of XHTML. HTML5, however, uses HTML parsing syntax, making the /> unnecessary for void elements. It is, however, valid to use it. Yes: <meta charset="UTF-8"> and <meta charset="UTF-8" /> are both acceptable.
Here’s the thing: a void element is not the same as an element that doesn’t contain any content. And ‘self-closing’ does not mean the same thing as “the end tag is optional.”
To state it clearly: Most HTML5 elements are not self-closing, but many elements do not require an end tag.
Wait, what? End tags are optional? It’s like HTML 3.2 all over again!
Yes, some HTML5 elements do not require an end tag. Those circumstances are outlined in the HTML5 specification. The p element, for example, does not require an end tag if the
p element is immediately followed by an address, article, aside, blockquote, dir, div, dl, fieldset, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, menu, nav, ol, p, pre, section, table, or ul, element, or if there is no more content in the parent element and the parent element is not an a element.
In fact, some tags can be omitted altogether. Browsers with compliant HTML5 parsers (such as the recently released Opera 11.5 snapshot) will add the end tags to the DOM.
But again: "end-tag optional" is a different concept than self-closing.
How about some examples?
Let’s take a look at the following bit of code:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>HTML tag example</title>
<link rel="stylesheet" href="styles.css" media="screen">
</head>
<body>
<header>
<hgroup>
<h1>When self-closing tags fail</h1>
<h2>Not all HTML5 elements are self closing, though some are ‘end tag optional’</h2>
</hgroup>
</header>
<article>
<p>This is to demonstrate that all HTML elements are <em>not</em> actually self closing. There is a "self-closed" <code>p</code> element following this closed paragraph. And it’s followed by a a "self-closed" <code>a</code> tag and another paragraph.</p>
<p id="notaselfclosinggraf" /><a id="notaselfclosinganchor" />
<p>As you can see, this paragraph is part of the preceeding link.</p>
</article>
</body>
</html>
You can view the code yourself. Notice that the last paragraph is actually treated as the link text of the of the supposedly self-closed link before it.
Let’s take a look at another example:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,user-scalable=yes,initial-scale=1.0"/>
<title>HTML tag example</title>
<link rel="stylesheet" href="styles.css" media="screen" />
<style>
.trigger1{
background: #369;
border-radius: 4px;
display:block;
padding:3px;
color:#fff;
}
#tvFinderImg{
background:#0c0;
display:block;
width: 10px;
height:10px;
}
#tvFinderImg h3{
border:1px dashed #c09;
}
</style>
</head>
<body>
<header>
<h1>Spans aren't self-closing either</h1>
</header>
<div>
<a
class="trigger1" href="#tvFindersrchd">Lorem ipsum <span id="tvFinderImg" /></a>
<p>This is some copy after the "self-closed" tag.</p>
</div>
</body>
</html>
In older browsers — Internet Explorer 8, for example — the supposedly self-closed tags are handled like unclosed tags. In those browsers, you will see a pink border around This is some copy after the “self-closed” tag.

In browsers that do have HTML5-compliant parsers — Firefox 4, the Opera 11.5 labs build mentioned above — the browser re-writes the DOM and adds a closing span tag. Yep. HTML5 saves developers from ourselves by providing rules for handling bad markup. View the DOM of that page in Opera 11.5 with Dragonfly, or Firefox 4 using Firebug (or in Chrome, Safari or IE9 using their developer tools) to see what I mean.
Let me restate this point for clarity: it only appears that self-closing tags are permitted in HTML5. In actuality, the browser parser treats non-void, self-closed tags as start tags and closes them for you.
Don’t believe me? Try running these pages through the W3C Markup Validator.
So I can go back to sloppy code?
Maybe. I think you can make an excellent argument for using relaxed markup rules when targeting end-users who may be paying per byte of bandwidth or who are on slow connections — Canadian mobile users, for example. Send less code. Make the browser handle it.
But keep in mind that older browsers do not have HTML5 parsers. Internet Explorer 7 & 8 do not. Opera 11.10 beta does not. Opera Mobile does not. (Older versions of WebKit technically don’t either, but WebKit has long supported the /> syntax.) If you have a large proportion of older browser users in your audience, stick to the stricter, XML-style syntax: if you have a start tag, use an end tag. The space-slash is optional for void elements. Don’t forget to validate!