Bruce Lawson's personal site

Why video, audio, canvas aren’t self-closing tags

I was having a chat with htmlboy about why some elements aren’t self-closing in HTML5, specifically <audio> and <video>.

One of the reasons is that by requiring a closing tag means you can delimit where fallback content begins and ends. It’s easy to see that in action:

<video src=nude-bruce.webm>
<p>Your browser doesn't support HTML5 video. Lucky you.</p>
<p>Millions panic when the above video caused retina failure.</p>

Everyone sees the line “Millions..” because it’s outside the starting and ending tags. The stuff between the tags is the fallback content.

The <canvas> element didn’t have an end tag when Apple dreamed it up, but Mozilla and Opera implemented a closing tag for exactly the same reason, and it got standardised with a closing tag.

Another model that could have been followed is having some kind of alt attribute on a self-closing element, much like <img> now, for example <video src=nude-bruce.webm alt="Your browser doesn't support HTML5 video. Lucky you." />.

The trouble with this is that attributes don’t contain markup, and we want to have download links in the fallback content:

<video src=kitten.webm>
<p><a href=kitten.webm>Download a kitten video</a>.</p>

Another problem with alt attributes is that generally authors have no control over the way they are presented – that’s up to the browser and beyond the control of CSS.

Interestingly (if you’re a weird geek like I am) the much-maligned XHTML2 understood this problem and changed good ol’ <img> so that it was no-longer a self-closing element, thus allowing fallback content between the tags just as I describe above:

In the following example, the W3C logo would be presented if it were available. If it were unavailable, then the enclosed text would be presented.

<img src="W3C.png">W3C</img>

So when HTML5 decided to adopt this idea from XHTML2 for <audio>, <video> and <canvas>, why didn’t they change the content model for <img> too?

Because of backwards compatibility. All existing browsers that I can find show the image and the fallback content. Neither do they allow me to change the colour of the fallback content in CSS (Try it out).

But the canvas and multimedia elements are new and have no backwards-compatibility to break, so they get the content model that allows for better fallback content.

Buy "Calling For The Moon", my debut album of songs I wrote while living in Thailand, India, Turkey. (Only £2, on Bandcamp.)

13 Responses to “ Why video, audio, canvas aren’t self-closing tags ”

Comment by Robin

Sidepoint: Firefox at least will style alt text with any styles applied to your image if the image breaks or doesn’t load due to settings.

Comment by Florent V.

Hi Bruce. When you write Fallback, it all boils down to what DOM structure the browser’s HTML parser will build. Since IMG is an empty element in HTML4 and XHTML1, as well as in the current HTML5 spec, browsers will simply consider that the tag is the full element, “Fallback” is some other content, and is an error that they should ignore. For the record, here is what you get (Firebug screenshot) for Fallback. So trying to style this illegal fallback content with CSS will obviously fail.

If we do want HTML fallback content for images, while not breaking backward compatibility, we have two options:

1. Use the OBJECT element. But both the HTML4 and HTML5 specs may be too vague to prompt browser vendors to update their OBJECT support (which is not that good right now I think).
2. Propose an IMAGE or PICTURE element for HTML5, working like VIDEO and AUDIO (with @src attribute, multiple SOURCE childs, HTML fallback content). That would be a way to (partly?) solve the @longdesc debate.

Comment by Bruce

Hi Florent

I’m not lamenting that we have no fallback for images. That way XHTML 2 lies. Alt works well enough.

I’m just pointing out that the idea of fallback was a good one for those new elements.

(Am doing some research r/e your question yesterday)

Comment by Florent V.

Why not both <video/> and <video>?

Because the HTML syntax in HTML5 allows you to write either or for elements that the spec defines as empty. (Long story short: “empty” means that they don’t have child nodes in the DOM.) Even if the spec didn’t allow it, authors (people writing HTML) and software are going to make mistakes. So browsers can’t rely on the presence of the / in the opening tag to decide if they should treat the element as empty or not (if the spec was crazy enough to allow some elements to be either empty or not!).

Backward-compatible HTML5 can’t redefine the IMG element as non-empty, that would break backward-compatibility and, in practice, break a lot of websites. And it can’t say that some elements can be either empty or not, because HTML parsers cannot make this work (XML parsers could, but most of the Web is not going to use XHTML5).

If you want to be backward-compatible, there is no other way than introducing a new element, or finally using an existing element that fits the bill (OBJECT) properly.
My favorite option would be to introduce a new element (IMAGE or PICTURE or GRAPHIC or whatever name) that works like AUDIO/VIDEO. OBJECT is nice but loaded with history, strange uses all over the Web, and incomplete or non-standard implementations. Plus, a new element would allow this kind of thing:

<picture width="300" height="200">
<source src="pic.svg" type="image/svg+xml" />
<source src="pic.png" type="image/png" />
<p>Long description of the picture.</p>

This purely fictional code would then mean: “My picture is 300px wide and 200px tall. Use the SVG source if you happen to support it. Otherwise, please use the PNG source. If you don’t support those formats or can’t get the source files or user doesn’t want images, read the fallback HTML content.” Wouldn’t that be neat?
(I wonder if this idea was already discussed — and then rejected — by the WHATWG.)

Comment by karl


The example could even be reduced too

Long description of the picture.

And use content negotiation server-side. It is already possible with IMG for example.

IMAGE is not possible because many browsers parsers make it an IMG element. GRAPHIC and PICTURE are not used to my knowledge.

Comment by Florent V.

Karl, thanks for the information. PICTURE might be a good candidate (“graphic” might not be, see “graphic content” in American English).
Regarding content negotiation, I have very little experience with that. It’s supposed to rely on the Accept HTTP header, but a quick test tells me that:
– Firefox 3.6 wants image/png for the src of IMG elements. If it can’t get that, it wants whatever image/* type it can get (so you can read this and serve SVG even though Firefox 3.6 doesn’t support it…).
– Firefox 4b8 asks the same thing as Firefox 3.6. Using the Accept header for those two browsers, you have no idea whether the browser does accept SVG or not.
– Chrome 7 and Safari 5 don’t send an Accept header for image files!

The state of the Accept header in Webkit and in Internet Explorer (up to version 8 at least) is downright ugly, as documented in this blog post. So we cannot rely on it. Unless there are more reliable content negotiation tools, from a practical point of view we have to ditch content negotiation and we’re back to the multiple SOURCE elements in HTML5. Browser developers seem to care a lot more for supporting this than for supporting HTTP.

Please correct me if I’m wrong.

Comment by Yuhong Bao

You forgot the biggest problem: Old browsers that do not recognize these tags at all and completely ignores them. For IMG, that was not a big problem because it was created early on in the history of HTML.

Comment by Yuhong Bao

“1. Use the OBJECT element. But both the HTML4 and HTML5 specs may be too vague to prompt browser vendors to update their OBJECT support (which is not that good right now I think).”
BTW, IE8 finally added proper support for displaying images using the OBJECT element.

Leave a Reply

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> . To display code, manually escape it.