A simple image gallery using only CSS and the :target selector

Back in the old days of web development and when CSS2 got support I always cringed at “CSS only” demos as a lot of them were hacky to say the least. With CSS growing up and having real interaction features it seems to me though that it is time to reconsider as – when you think about it – visual effects and interactivity should be maintained in the CSS rather than in JavaScript and CSS.

With the support we have in new browsers it would be a waste not to use what has been put in. If you have to give all the visual candy to IE6, OK, then you’d have to use a library like jQuery for your effects. But you can have your cake and eat it if you don’t give the shiny to the old browsers out there, but give them a simpler interface and make sure they don’t get what they don’t understand.

So today let’s take a look at an image gallery using the target selector. This has been done before (lightbox example, thumbnail preview example) but I thought it’d be good to explain the details of what is going on.

So here is a screencast of our “CSS only image gallery” in action and you can see it for yourself.

Starting with HTML

We start with HTML that works across all browsers (except for IE < 9, where you need a polyfill to style HTML5 elements):

Without any CSS this would just show all the kitten images in a vertical row and the links would point to them. This works, and should be more than enough for the IE6 users out there.

For browsers that support newer CSS, however, we can turn this into our gallery in a few easy steps:

Step 1: Position the articles

To make sure we don’t give IE older than 9 any CSS it chokes on, we can wrap all the selectors in a simple media query (in this case checking that the window is at least 400 pixels wide):

@media screen and (min-width: 400px) {
  ... all the good stuff ...

We then can give the gallery dimensions and an overflow of hidden to make sure that elements positioned outside of it will not be shown. We also position it relative so that every positioned child element will be positioned relatively to it:

.gallery {
  position: relative;
  height: 280px;
  width: 340px;
  overflow: hidden;

Then we position all the target elements absolutely in the gallery with 320 pixels to the left. This hides them off screen as we hide the overflow:

.target {
  position: absolute;
  top: 60px;
  left: -320px;
  height: 220px;
  width: 300px;

Now in order to show the image when the link to it was clicked we use the :target selector. This one assigns the CSS to the element when it was targeted – either by activating a link to it in the document or from the URL when the page loaded. With this pseudo selector, we override the left setting and move it to 20 pixels, thus showing the image.

.target:target {
  left: 20px;

You can try this out for yourself:

JSFiddle demo.

To make this smoother, all we need to do is to add a CSS transition to the target styles. Now all the changes to the styles will happen smoothly during a second rather than immediately.

.target {
  position: absolute;
  top: 60px;
  left: -320px;
  height: 220px;
  width: 300px;
  -webkit-transition: 1s;
     -moz-transition: 1s;
      -ms-transition: 1s;
       -o-transition: 1s;
          transition: 1s;

Again, see it in action and play with it.

JSFiddle demo.

That is all there is to it – the rest of the effects are just different variations of the same trick – animating opacity from 0 to 1 or CSS transitions.

Target selectors can be a very powerful trick. The main issue they have though is that the page scrolls to the target, so if there is a big distance between the link and the target you’ll get unsightly jumps.

About Chris Heilmann

Evangelist for HTML5 and open web. Let's fix this!

More articles by Chris Heilmann…


  1. VenomVendor

    Effect Top is Coool

    February 21st, 2012 at 17:43

  2. iamvdo

    You can avoid the jump to the target using a display:none element and the general sibling selector (~)

    Here is a demo (in french): http://www.css3create.com/Astuce-Empecher-le-scroll-avec-l-utilisation-de-target


    February 22nd, 2012 at 00:38

  3. Bart

    Amazing, neat markup and works very well.

    And i liked this bit: “This works, and should be more than enough for the IE6 users out there.”

    Well said! They can’t appreciate cool stuff anyway so let em scroll!

    February 22nd, 2012 at 04:33

  4. aceman

    But don’t forget that Firefox does decode and keep in memory all images on the page even those that aren’t visible. Keep this in mind before stuffing 100 large images in this gallery. Other browsers do this better. There is a bug on bugzilla for this if you are interested.

    (P.S. please fix the captcha text below, it does not have the character encoding specified properly so it shows diacritical characters wrongly (it seems the captcha instructions are localized for each visitor). I get “Mus�me sa uisti?, ?e ste ?lovek. Vyrie?te zadanie ni??ie a kliknite na tla?idlo Som ?lovek. Z�skate tak k�d potvrdenia. Ak chcete tento proces v bud�cnosti zjednodu?i?, odpor�?ame v�m povoli? jazyk JavaScript.”).

    February 22nd, 2012 at 04:54

  5. Beben Koben

    i love this trick…thanks for coding

    February 22nd, 2012 at 08:29

  6. George Zamfir

    Positioning the hidden images JUST off-screen will still make them available to assistive technologies (ie screen readers) while not visually displayed.

    Consider toggling between display: none & display: block

    February 22nd, 2012 at 09:10

  7. sometwothings

    Yet this means that if you look through an image gallery and would like to return to the place before, you will need to either click back (or hit backslash) several times or click it for a long time, waiting for the dropdown, instead of clicking back once to return.

    February 22nd, 2012 at 15:39

  8. dianne

    for IE9 the images don’t show unless you change to compatibility mode…

    February 23rd, 2012 at 06:36

  9. Jakob

    Thank you for sharing your knowledge with us! I did not know about the “:target” pseudo selector, but this article is a good starting point.

    Kind regards

    March 8th, 2012 at 08:39

Comments are closed for this article.