Create a lightbox with CSS3

The days of using javascript lightboxes are over!

Just kidding, javascript lightboxes remain a much more efficient and cross-browser friendly way of doing achieving the lightbox effect. This CSS3 lightbox tutorial is for demonstration purposes only. I’m doing this because it’s interesting to see how far you can push CSS and you end up learning quite a lot. I do at least.

The HTML

The HTML isn’t very semantic at all.

<div id="page-wrap">
  <div id="lightbox">
    <div id="img1">
        <img src="images/beatles.gif" width="920" alt="" />
        <a class="close" href="#"></a>
    </div>
    <div id="img2">
        <img src="images/brand-new.jpg" width="520" alt="" />
        <a class="close" href="#"></a>
    </div>
    <div id="img3">
        <img src="images/the-killers.jpg" width="920" alt="" />
        <a class="close" href="#"></a>
    </div>
  </div>
  <ul id="gallery">
    <li>
      <a class="clearfix" href="#img1">
        <img src="images/beatles.gif" alt="The Beatles" width="200" />
        <span>The Beatles</span>
      </a>
    </li>
    <li>
      <a class="clearfix" href="#img2">
        <img src="images/brand-new.jpg" alt="Brand New" width="200" />
        <span>Brand New</span>
      </a>
    </li>
    <li>
      <a class="clearfix" href="#img3">
        <img src="images/the-killers.jpg" alt="The Killers" width="200" />
        <span>The Killers</span>
      </a>
    </li>
  </ul>
</div>

As you can see, there is quite a lot of markup, some of it even looks — and is — unnecessary, such as <a class="close" href="#"></a> which appears as many times as there are lightbox images.
There are obviously no “for each”, “append” or “prepend” functions in HTML or CSS so all of this is done manually. Each gallery image-thumbnail has a corresponding lightbox image. Each lightbox image contains a close button. I’ve also set a width to the gallery images, this forces a width but allows for a dynamic height while keeping the image in proportion.

The <span> elements are going to be used as a caption.

The CSS

#page-wrap {
  margin: 0 auto;
  position: relative;
  width: 980px;
}
#gallery {
  display: table;
  margin: 0 auto;
}
#gallery li {
  float: left;
  margin: 10px 20px 0 0;
  position: relative;
}
#gallery span {
  background: rgba(0, 0, 0, 0.7);
  opacity: 0;
  padding: 10% 0;
  width: 100%;
  text-align: center;
  position: absolute;
  left: 0;
  bottom: 0;
  -moz-transition: opacity 0.6s ease-in;
  -o-transition: opacity 0.6s ease-in;
  -webkit-transition: opacity 0.6s ease-in;
}
#gallery li:hover span {
  opacity: 1;
}
#gallery a {
  border: 5px solid rgba(0, 0, 0, 0.1);
  display: block;
  position: relative;
  -moz-transition: border 0.6s ease-out;
  -webkit-transition: border 0.6s ease-out;
  transition: border 0.6s ease-out;
}
#gallery a:hover {
  border: 5px solid rgba(39, 25, 0, 1);
  border: 5px solid rgba(0, 0, 0, 0.5);
}
#gallery a:focus {
  -moz-transform: rotate(-2deg);
  -webkit-transform: rotate(-2deg);
  transform: rotate(-2deg);
}
#gallery img {
  float: left;
}
#lightbox div {
  background: #fff;
  border: 30px solid #fff;
  opacity: 0;
  position: absolute;
  left: 0;
  top: 6%;
  z-index: 0;
  border-radius: 10px;
  box-shadow: 0 0 40px rgba(0, 0, 0, 0.4);
  -webkit-transition: all 0.3s ease-out;
  -moz-transition: all 0.3s ease-out;
  transition: all 0.3s ease-out;
}
#lightbox div:target {
  opacity: 1;
  z-index:10
}
#lightbox img {
  float: left;
  border-radius: 3px;
}
#lightbox #img2 {
  left: 15%;
}
#lightbox a {
  background: url(../images/close.png) no-repeat left top;
  height: 28px;
  width: 30px;
  position: absolute;
  top: -42px;
  right: -42px;
}

Al right, time to break this thing down.
#gallery {display: table; margin: 0 auto} – This centres something that has a dynamic width. Yes that’s right folks, if you add another item it will still be centred. Very awesome, simple and handy.

I’ve set the transition property on #lightbox div to ‘all’. Why not just do this for opacity? Because the z-index also needs to be animated. If transition isn’t applied to z-index, it fades away after immediately falling beneath a couple of elements. I had no idea you could apply a transition to z-index before this. After tinkering for a while I finally gave it a try and it works perfectly in Firefox 4 and Webkit.

What is :target

The pseudo class that is responsible for this whole experiment is :target. Target is quite a simple concept, and it can really broaden your ideas as to what CSS can actually do.

Let’s say you have a url: http://css-plus.com/
Whatever CSS properties you apply to:

#footer:target{
	/* Apply properties here */
}

Will affect #footer when the url changes to this: http://css-plus.com/#footer

Therefore, when you click the “back” button on your browser after clicking around for a while in the demo

How does this work in almost-plain-English?

You click an anchor link with a hash value equal to that of an ID. Once this happens, the :target pseudo-class kicks in and the properties it contains take effect. The transition property on the ID then takes effect

The close button isn’t really a “close” button. It’s an anchor link that contains a different hash value to the value in the in the URL. Once this “close” button is clicked, the previously :targeted id is not targeted any more. Therefore it loses the z-index and opacity properties that were applied to it. Once this happens the transition property takes affect again and this creates the “fade out” effect.

Problems I ran into

I wasn’t able to recreate the transparent black overlay that normally accompanies a lightbox. – I’m sure there is a way of doing this, I just haven’t figured it out yet. If you know of a way let me know and I’ll update this.

Conclusion

This was a fun experiment which shows you that there are many things that can be done with CSS.

Any questions or comments?

  1. Connor says:

    Awesome, I ‘ve been working on a similar effect for a while now came about it a little differently. I’m still trying for the backlight, but anything I try dealing with opacity I’ll end up with the focused image transparent as well. It’s maddening!

    1. Jamy Golden says:

      Haha! Yeah, it does take a bit of time, but… Persevere! Good luck and let me know when you’re done =)

  2. droll says:

    Very nice, just the sort of thing I’ve been wanting to do for a friend/artist/client website. May also try adapting it for my own unfinished photography site.

    But the Demo page is odd in IE8: the large image of “The Killers” appears behind the thumbnails, in front of and obscuring part of the page’s header area but behind the title, and rendering part of “return to post” illegible (white border of the large image partly overlapping white text). And the other two thumbnails don’t bring up their respective large images.

    1. Jamy Golden says:

      Thanks =)

      The tut is mainly just to show the power of CSS. It’s not really meant to be used in the real world (yet) due to LT IE9 still being around. For awesome lightboxes that will work perfectly on IE6+ I suggest having a look at Colorbox and Fancybox.

  3. Css says:

    Nice sharing i like demo as well.

  4. wiyono says:

    How to make next and prev button?

    Thank you

    1. Jamy Golden says:

      That would require javascript and this is meant to be a CSS3 only lightbox. I suggest you have a look at colorbox if you’d like a functional lightbox.

    2. wiyono says:

      Thanm you, this is great, in Windows Phone have no Problem, perfect, good job, thanks

  5. Hello,
    awesome approach and result. I use Lightbox with javascript a lot, but when it comes to eBay-article HTML, javascript is not allowed. But with css I now can offer a similar way. Thank you!

Leave a Reply to wiyono Cancel reply