Oli.jp

Articles…

Questioning the HTML5 outline algorithm

I recently received this email about the outline algorithm from Thomas Hühn, and thought the reply might benefit others.

I've got a document:

<!DOCTYPE html>
<title></title>
<article>
<h1></h1>
<h2></h2>
<aside></aside>
<h3></h3>
</article>

The resulting outline seems to be:

(article)
 (h1)
   (h2)
   (aside)
   (h3)

That is, aside interrupts the header hierarchy, causing the h3 to start its own header context on the same level as the h2 (and thus it doesn't matter whether the h3 is a h3 or a h2).

What I would like to have is this:

(article)
 (h1)
   (h2)
   (aside)
     (h3)

where the h3 is a child of h2. The aside is only there to explain a point made in the h2 (in the original, non-test document there are quite a few paragraphs under all those headings, but being a minimal example I deleted those).

Can I make the h2/h3 to stay together in one hierarchy of headers?

We are planning some in-depth articles on the outline algorithm at HTML5Doctor, but until then you can check the spec on making an outline. I also cover it a little in an article I wrote about HTML5 structure.

So as you can see in the spec if you’re not using explicit sectioning elements around heading elements (<h1><-h6>), the outline algorithm pretends they were there. So your code sample:

<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<article>
<h1>Title 1</h1>
<h2>Title 2</h2>
<aside>Aside</aside>
<h3>Title 3</h3>
</article>
</body>
</html>

is treated as if it were:

<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<article>
<h1>Title 1</h1>
<section>
<h2>Title 2</h2>
</section>
<aside>Aside</aside>
<section>
<h3>Title 3</h3>
</section>
</article>
</body>
</html>

This has the outline you describe:

(article)
 (h1)
   (h2)
   (aside)
   (h3)
because the <h2> section, the <aside> and the <h3> section are all siblings.

The reason you’re not getting the outline you expect is because <aside> is one of the four sectioning elements. This interferes with the outlining algorithm, which assumes if you’re using sectioning elements you’re using them everywhere they’re appropriate.

If you used <div> instead of aside you get:

(article)
 (h1)
   (h2)
     (h3)

To get the correct outline you need to use explicit sectioning element wrappers:

<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<article>
<h1>Title 1</h1>
<section>
<h2>Title 2</h2>
<aside>Aside</aside>
<section>
<h3>Title 3</h3>
</section>
</section>
</article>
</body>
</html>

This gives the outline:

(article)
 (h1)
   (h2)
     (aside)
     (h3)

Note that <h3> must be a child of the sectioning element containing <h2>, and this will also make <aside> a child of the <h2> section too.