demosthenes.info

A blog by Dudley Storey on , , , , , , and anything else that strikes his fancy.

featured articles

popular favourites

Hong Kong
Hong Kong Skyline at Night
Monument ValleyMonument Valley
Monument Valley

HTML5 Image Captions With CSS3 Transition Effects

Instances of this navigation have been appearing around the web recently, so I decided to code my own version and make it a short lesson. These effects might be useful for a gallery, or on any site that was navigated primarily through visual media.

We’ll use HTML5 markup for the navigation, although we could just as easily use definition lists if we wanted to stick with XHTML.  In the examples above I show two versions of the effect: an image cross-fade and a long scroll, both with captions that slide into place. The HTML5 markup looks something like this:

  1. <figure id=hong-kong">
  2. <a href="#"><img src="hong-kong.jpg" style="width: 439px;" /></a>
  3. <figcaption>Hong Kong Skyline at Night</figcaption>
  4. </figure>
  5. <figure id=monument-valley">
  6. <a href="#">
  7. <img src="monument-valley-dawn.jpg" style="position: absolute; left: 0;" />
  8. <img src="monument-valley-moonrise.jpg" /></a>
  9. <figcaption>Monument Valley</figcaption>
  10. </figure>

(I’ve removed alt and title attributes from the images for the sake of convenience, in order to shorten the code. While the images shouldn’t appear linked in modern browsers, you would want to use a CSS reset to eliminate that default appearance in older browsers. )

The <figure> elements will be given a fixed height and width that contains the standard image. We’ll also give each <figure>  a position of relative, which will come in handy with moving our captions later. overflow is set to hidden to hide anything outside these dimensions:

  1. figure { position: relative; width: 350px; height: 150px; overflow: hidden; }

The fig caption element is given an rgba background-color, while taking position: absolute:

  1. figcaption {
  2. background: rgba(0,0,0,0.3); width: 100%; color: #fff; padding: 8px;
  3. position: absolute; }

(Technically, only the second navigation example requires absolute and relative positioning; I’ve applied the properties to both out of convenience).

overflow: hidden applied to each <figure> hides the <figcaption>. Making that caption rise when we are over the image is very simple: simply attach a :hover pseudo-selector to the <figure> that changes the position of the descendant <figcaption>.  (Remember, we can place hover effects on most anything.) I’ll also specify this as :focus for touchscreen devices without support for hover, such as iPhones.

  1. figure:hover fig caption, figure:focus fig caption  { margin-top: -35px; }

We want to ease that change with a transition:

  1. figcaption { -webkit-transition: .7s all linear;
  2. -moz-transition: .7s all linear;
  3. -ms-transition: .7s all linear;
  4. -o-transition: .7s all linear;
  5. transition: .7s all linear; }

Then we want to animate the images inside each <figure>. For the first example, this is relatively straightforward. First of all, the image is not 350 pixels wide, as claimed by our CSS. We’ll correct that with an inline style:

  1. <a href="#"><img src="hong-kong.jpg" style="width: 439px;" /></a>

The panoramic photograph of Hong Kong by Gary Elsasser is still cut off by the size of the <figure> element and the fact that any overflow is hidden. Moving the image on hover is accomplished in much the same way as we did the captions:

  1. figure#hong-kong:hover img, figure#hong-kong:focus img {
  2. margin-left: -80px;
  3. -webkit-transition: 4s all linear;
  4. -moz-transition: 4s all linear;
  5. -ms-transition: 4s all linear;
  6. -o-transition: 4s all linear;
  7. transition: 4s all linear; }

The example with the photographs of Monument Valley (by Alex Proimos and Ernesto Andrade, respectively) is a little trickier. First, we must position one image on top of another. That means another brief application of an inline style:

  1. <a href="#">
  2. <img src="monument-valley-dawn.jpg" style="position: absolute; left: 0;" />
  3. <img src="monument-valley-moonrise.jpg" />
  4. </a>

The image of Monument Valley at dawn will automatically appear on top of the other photograph. We want to fade out the first image on hover / focus, which we’ll accomplish with a use of first-child:

  1. figure#monument-valley:hover img:first-child {
  2. opacity:0;
  3. -webkit-transition: 4s all linear;
  4. -moz-transition: 4s all linear;
  5. -o-transition: 4s all linear;
  6. -ms-transition: 4s all linear;
  7. transition: 4s all linear;  }

There’s one small remaining issue. Because the <figcaption> elements appear on top of the images, they capture any mouse activity in the bottom 35 pixels of the <figure> element. Only the images are linked: if the user’s mouse happens to be over a caption, there’s effectively no link, as the caption will "capture" any mouse events. There’s two ways around this:

  1. Write another link around the fig caption. (Not wrong, but slightly annoying, especially as you’ll have to style the <a> element that is added).

  2. Turn off pointer effects for the fig caption element, making any mouse clicks pass through it to be captured by the links on the images underneath.

The latter is obviously the easiest option, but right now has less support than the first. I’ll use it all the same. The completed code is:

The CSS:

  1. figure { position: relative; width: 350px; height: 150px;
  2. overflow: hidden; float: left; }
  3. figure img { width: 350px; height: 150px; }
  4. figure fig caption { background: rgba(0,0,0,0.3);
  5. width: 100%; color: #fff; padding: 8px; margin-left: 0;
  6. position: absolute; -webkit-transition: .7s all linear;
  7. -moz-transition: .7s all linear; -ms-transition: .7s all linear;
  8. -o-transition: .7s all linear;
  9. transition: .7s all linear;
  10. pointer-events: none; }
  11. figure:hover fig caption, figure:focus fig caption { margin-top: -35px; }
  12. figure#hong-kong:hover img, figure#hong-kong:focus img
  13. { margin-left: -80px;
  14. -webkit-transition: 4s all linear;
  15. -moz-transition: 4s all linear;
  16. -ms-transition: 4s all linear;
  17. -o-transition: 4s all linear;
  18. transition: 4s all linear; }
  19. figure#monument-valley:hover img:first-child
  20. { opacity:0;
  21. -webkit-transition: 4s all linear;
  22. -moz-transition: 4s all linear;
  23. -ms-transition: 4s all linear;
  24. -o-transition: 4s all linear;
  25. transition: 4s all linear;  }

The HTML:

  1. <figure id=hong-kong">
  2. <a href="#">
  3. <img src="hong-kong.jpg" style="width: 439px;" />
  4. </a>
  5. <figcaption>Hong Kong Skyline at Night</figcaption>
  6. </figure>
  7. <figure id=monument-valley">
  8. <a href="#">
  9. <img src="monument-valley-dawn.jpg" style="position: absolute; left: 0;" />
  10. <img src="monument-valley-moonrise.jpg" />
  11. </a>
  12. <figcaption>Monument Valley</figcaption>
  13. </figure>

web developer guide

featured comment

by JoelB in Goodbye, JQuery Validation: HTML5 Form Errors With CSS3

what i'm reading

A Storm of Swords: A Song of Ice and Fire: Book Three
A Storm of Swords: A Song of Ice and Fire: Book Three

what i'm watching

Californication: The Third Season
Californication: The Third Season

what i'm playing

Mass Effect 3 Collector's Edition
Mass Effect 3 Collector's Edition

what i'm hearing

Dub FX
Dub FX

blogs

podcasts

no ads ever

This blog is free of advertising, and always will be.

creative commons licensed

The content of this blog is free to use in whatever way you wish under the Creative Commons license.