Marking up a slideshow in HTML5
I’ve been known to rewrite the HTML, CSS, and JavaScript I use for slideshows almost as often as I give presentations. In the past few weeks, I’ve given three talks about HTML5 or related technology, so I used the opportunity to put some thought into how HTML slideshows should be marked up in HTML5.
The
spec introduces several new sectioning
elements to HTML:
<article>
,
<section>
,
<header>
&
<footer>
,
<nav>
,
<aside>
, and
<hgroup>
.
Unlike some
critics, I don’t think these elements are just for putting
magazine articles on the web
—they’re generally useful in a
variety of situations.
For slideshows, <article>
is a great match
for the deck itself, while you can use
<section>
for each slide. I use the semantic
class name deck
to distinguish slideshow
articles from other kinds of articles.
<article class="deck">
… slides go here …
</article>
I use <header>
and <footer>
children of <article>
for material repeated
at the top and bottom of every slide.
<article class="deck">
<header>
<h1>Presentation Title: Presentation subtitle</h1>
</header>
… slides go here …
<footer>
<address class="vcard">
<a href="/" class="url fn">Theresa O’Connor</a>
</address>
</footer>
</article>
Each slide ends up looking like so:
<section>
<h2>Something</h2>
<p>Something something</p>
</section>
On the very first (title) slide, I break up the presentation
title and subtitle into separate hN
elements, but I don’t want the subtitle to affect the document
outline. This is precisely the situation the <hgroup>
element is intended for.
<section>
<hgroup>
<h1>
<a href="link-to-slides" rel="bookmark">Presentation Title</a>
</h1>
<h2>Presentation subtitle</h2>
</hgroup>
</section>
Navigation
I’d like to be able to advance the slides with
SPC or the arrow keys, but also with
explicit buttons on-screen. Such buttons allow the user to
navigate between the slides, and so this might be a good fit for
the new <nav>
element.
<nav> <ul> <li><button id="previous-slide">Previous</button></li> <li><button id="next-slide">Next</button></li> </ul> </nav>
// The corresponding JavaScript $('#previous-slide').click(previous_slide); $('#next-slide').click(next_slide); // Listen for keypresses as well $('html').bind('keydown', handle_keys);
For presentation formats like Ignite or Pecha Kucha Night slides need to be advanced automatically by JavaScript. Instead of Previous and Next buttons, a simple play button will do.
<nav> <ul><li><button id="play">Play</button></li></ul> </nav>
// The corresponding JavaScript function play() { setInterval(next_slide, 15*1000); return false; } … $('#play').click(play);
Bookmarking
I’d be nice if each slide were individually bookmarkable. Since
the slides are HTML, we can place id=""
attributes on each slide, with meaningful IDs that fit each
slide’s content. Now each slide will look like this:
<section id="slide-slug">
<h2>Something</h2>
<p>Something something</p>
</section>
This implies two things about our JavaScript.
-
At page-load time, we’ll need to jump to the correct slide if there’s a fragment in the URL.
$(document).ready(function() { … // If there's a hash, start there instead of the first slide if (location.hash != "") { set_current_slide(slides.index($(location.hash).get(0))); } else { set_current_slide(0); } });
-
At slide-change time, we’ll need to update the fragment in the URL to match.
function set_current_slide(index) { var slide = $(slides.get(index)); // Show this slide and hide the other ones. slides.not(slide).hide(); slide.show(); // Update hash if this slide has an @id // P.S. JavaScript could use an anaphoric `if'. var id = slide.attr('id'); if (id) { location.hash = id; } }
What about older browsers?
Older browsers differ wildly in their handling of unkown elements, so you may need to employ several workarounds to use these new elements.
For IE, the most excellent html5shiv makes
the browser recognize new elements. It’ super easy to use: just
drop one <script>
into place with a
conditional comment, and you’re good.
IIRC, some older Firefoxen will treat unrecognized elements as
inline unless you style them as display: block
in a <style>
element directly in the
HTML, like so:
<!-- Make older browsers handle new elements. -->
<style>
article, footer, header, hgroup, nav, section {
display: block;
}
</style>
If you’d like to see how it all adds up, take a look at any of the three decks I linked to above, or take a peek at presentation.css and presentation.js.