TUTORIAL

Creating an Photograph Gallery using CSS only

Introduction

One of the many uses for personal and professional web site is to display a gallery of photographs that show off your skills with a camera. Until now these galleries have been produced using javascript, PHP or CGI.

However there is now another way.

With this article I hope to show you how to produce a professional quality photograph gallery using nothing more than an unordered list of photographs and a Cascading Style Sheet (CSS). I will take you through the styling one step at a time and end up converting:

Each step will be thoroughly explained and have an example page showing the effect of the additional styling so that you can see what to expect.

The photograph gallery will work in all the latest browsers and I have included hacks enabling Internet Explorer 5.5 to interpret the style correctly. The styling is not too long or difficult, but the layout will need a lot of attention to detail and pre planning.

Method

Step 1

The images

I have found that this gallery will load fairly quickly with up to twelve medium sized (approximately 400px x 250px and 15-20KB) images, as it requires all the images to be preloaded before it will work. Any more than this will cause the page loading time, in my opinion, to become unacceptable. You may find that this is not the case with your images but it is best to test this out before you begin.

Start with your basic unordered list and see how long this takes to load (emptying your cache before you do so). I have chosen twelve images of dogs comprising 6 in portrait format and six in landscape. The basic (x)html list is given below.

<div id="container">
  <ul>
    <li>
      <img src="../images/p1.jpg" alt="Alpha" title="Alpha" />
      <br />
      ALPHA
      <br />
      Photographed by Dorota Mrowka, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p2.jpg" alt="Minie" title="Minie" />
      <br />
      MINIE
      <br />
      Photographed by José Antonio Assis, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p3.jpg" alt="Megan" title="Megan" />
      <br />
      MEGAN
      <br />
      Photographed by Rob Waterhouse, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p4.jpg" alt="Nancy" title="Nancy" />
      <br />
      NANCY
      <br />
      Photographed by Philip Keller, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p5.jpg" alt="Missy" title="Missy" />
      <br />
      MISSY & PANDA
      <br />
      Photographed by Kat Shurtz, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p6.jpg" alt="Stray pup" title="Stray pup" />
      <br />
      STRAY PUP
      <br />
      Photographed by Bethan Hazell, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p7.jpg" alt="Rolo" title="Rolo" />
      <br />
      ROLO
      <br />
      Photographed by Paul Leach, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p8.jpg" alt="Gigio" title="Gigio" />
      <br />
      GIGIO
      <br />
      Photographed by Davide Guglielmo, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p9.jpg" alt="Westy pup" title="Westy Pup" />
      <br />
      WESTY PUP
      <br />
      Photographed by Rob Waterhouse, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p10.jpg" alt="Giga Byte" title="Fishing" />
      <br />
      GIGA BYTE
      <br />
      Photographed by Jefras, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p11.jpg" alt="Puppy" title="Puppy" />
      <br />
      PUPPY
      <br />
      Photographed by Clodiney Cruz, courtesy of the stock.xchng
    </li>
    <li>
      <img src="../images/p12.jpg" alt="Buffy" title="Buffy" />
      <br />
      BUFFY
      <br />
      Photographed by Rob Waterhouse, courtesy of the stock.xchng
    </li>
  </ul>
</div>

My images are either 372px high by 240px wide (portrait format) or 240px high by 372px wide (landscape format). These sizes have been calculated for several reasons, namely:

  1. To enable the gallery to fit within a screen resolution of 800 x 600 pixels without the need for scrolling.
  2. To give thumbnail images of 93px by 60px (a quarter full size), which I consider is just large enough to give a good definition of the full size image.
  3. To enable me to place three portrait thumbnails OR two landscape thumbnails in a line using a border of 1 pixel and a left / right margin of 2 pixels.

A horizontal row of three portrait images, 60px wide, each one having a border of 1px and a left / right margin of 2px gives a total width of 3 times 66px which is 198px.

A horizontal row of two landscape images, 93px wide, each one having a border of 1px and a left / right margin of 2px gives a total width of 2 times 99px which is also 198px.

I find it best to sketch out a rough plan of the gallery before I begin to add the styling, this way I can calculate the best size for my thumbnails and full size images. A little bit of thought 'up front' will save a lot of frustration and redesign.

Step 2

The !DOCTYPE

Firstly and most importantly, make sure that you have the correct (X)HTML !DOCTYPE. Without this most browsers will be thrown into 'quirks' mode which will lead to all sorts of incompatibility problems. W3C QA - List of valid DTDs has a list of valid DOCTYPES that can be used. Select from XHTML1.0 or XHTML1.1 as these are more suitable for this styling. I use XHTML1.1 for all my current web pages.

Step 3

Adding links and style information

In order that I can use the :hover pseudo class style I need to change the basic unordered list into an unordered list of links. This is because Internet Explorer will only allow :hover to be used on links. I also need to add extra markup to target specific images.

The (x)html will now look like this.

<div id="container">
  <ul>
    <li>
      <a class="gallery slidea" href="#nogo">
        <span>
          <img src="../images/p1.jpg" alt="Alpha" title="Alpha" />
          <br />
          ALPHA
          <br />
          Photographed by Dorota Mrowka, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slideb" href="#nogo">
        <span>
          <img src="../images/p2.jpg" alt="Minie" title="Minie" />
          <br />
          MINIE
          <br />
          Photographed by José Antonio Assis, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidec" href="#nogo">
        <span>
          <img src="../images/p3.jpg" alt="Megan" title="Megan" />
          <br />
          MEGAN
          <br />
          Photographed by Rob Waterhouse, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slided" href="#nogo">
        <span>
          <img src="../images/p4.jpg" alt="Nancy" title="Nancy" />
          <br />
          NANCY
          <br />
          Photographed by Philip Keller, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidee" href="#nogo">
        <span><img src="../images/p5.jpg" alt="Missy" title="Missy" />
          <br />
          MISSY & PANDA
          <br />
          Photographed by Kat Shurtz, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidef" href="#nogo">
        <span>
          <img src="../images/p6.jpg" alt="Stray pup" title="Stray pup" />
          <br />
          STRAY PUP
          <br />
          Photographed by Bethan Hazell, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slideg" href="#nogo">
        <span>
          <img src="../images/p7.jpg" alt="Rolo" title="Rolo" />
          <br />
          ROLO
          <br />
          Photographed by Paul Leach, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slideh" href="#nogo">
        <span>
          <img src="../images/p8.jpg" alt="Gigio" title="Gigio" />
          <br />
          GIGIO
          <br />
          Photographed by Davide Guglielmo, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidei" href="#nogo">
        <span>
          <img src="../images/p9.jpg" alt="Westy pup" title="Westy Pup" />
          <br />
          WESTY PUP
          <br />
          Photographed by Rob Waterhouse, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidej" href="#nogo">
        <span>
          <img src="../images/p10.jpg" alt="Giga Byte" title="Fishing" />
          <br />
          GIGA BYTE
          <br />
          Photographed by Jefras, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidek" href="#nogo">
        <span>
          <img src="../images/p11.jpg" alt="Puppy" title="Puppy" />
          <br />
          PUPPY
          <br />
          Photographed by Clodiney Cruz, courtesy of the stock.xchng
        </span>
      </a>
    </li>
    <li>
      <a class="gallery slidel" href="#nogo">
        <span>
          <img src="../images/p12.jpg" alt="Buffy" title="Buffy" />
          <br />
          BUFFY
          <br />
          Photographed by Rob Waterhouse, courtesy of the stock.xchng
        </span>
      </a>
    </li>
  </ul>
</div>

Style Ready List

Every list item is now enclosed in a link which has a common 'gallery' class and a unique 'slide letter' class. They are also further enclosed by a span which does not have any specific class or id.

I have used href="#nogo" instead of the more usual href="#" so that anyone clicking the link will not jump to the top of the page (just make sure you do not have an anchor #nogo on your page). You can, if you wish use this to link to take visitors to a larger image on a new page.

The (x)html unordered list is now complete and I will not need to make any more changes to it.

The Styling

Step 4

The body

The <body> is first to be styled with the font-family for the whole page. I have chosen Tahoma as the first choice but you can select any font you wish. I have also chosen a font size of 76% as this is gives a suitable default size for most screen resolutions. It also allow Internet Explorer users to resize the font if they wish.

/* choose a suitable font and center the #container div in Internet Explorer */
body {
   text-align:center; 
   font-family: tahoma; arial, sans-serif; 
   font-size:76%; 
   letter-spacing:0.05em;
   }

I have added text-align:center; so that Internet Explorer will place the #container div centrally (left / right) on the page. This will ONLY target Internet Explorer and Opera, all other browsers will ignore this styling. I will use the 'correct method' as described in Step 4 to target all other browsers.

Example #1

Step 5

The container

In order that the gallery can be viewed at a resolution of 800 x 600 I will limit the #container div to a fixed size of 770px wide by 396px high. I will also add a 1px thick grey border.

This is fairly straightforward to style as below.

/* The containing box for the gallery. */
#container {
    position:relative; 
    width:770px; 
    height:396px; 
    margin:20px auto 0 auto; 
    border:1px solid #aaa; 
    }

Example #2

I have given this div a relative position so that I can position the gallery images within it using absolute positions. The margins have been given a left / right value of auto so that all browsers, except Internet Explorer (which has been taken care of in Step 3 above), will center the div (left / right) on the page.

Depending on which browser you are using you will see either the images overflowing the container or the images held within an expanded container. The 'correct' interpretation is that the images should overflow the container.

Step 6

Removing the bullets

I will need to style the unordered list by removing the bullets and the indentation.

Browsers have different ways of doing this, Internet Explorer and Opera use margin values for the indentation whereas Mozilla/Netscape/Firefox all use padding values, so to cater for this I need to style the list as follows.

/* Removing the list bullets and indentation */
#container ul {
    padding:0; 
    margin:0; 
    list-style-type:none; 
    }

Example #3

Now the bullets are gone.

Step 7

Removing the images

Well almost removing them.

In order that the images are preloaded I must actually display them on the screen but make them 'invisible'. I can do this by putting them in a container (span) size of 1px by 1px and use an identical absolute position for each one so that the are displayed on top of one other. This will have the effect of displaying only the top left pixel of each image and showing a 1px 'dot' in the #container div.

This will also hide the text associated with each image.

/* Remove the images and text from sight */
#container a.gallery span {
    position:absolute; 
    width:1px; 
    height:1px; 
    top:5px; 
    left:5px; 
    overflow:hidden; 
    background:#fff;
    }

Example #4

If you look very closely in the top left hand corner of the #container div you will see a 1px black dot. If you change the absolute position to top:-1px; left:-1px; the dot will be placed over the grey border of the #container div., the position of the dot can be anywhere on the screen, the choice is yours.

The span overflow has been set to hidden to make sure that the rest of the image and the associated text is not displayed.

Other than this dot, the #container div should now be empty.

Step 8

Adding the thumbnails

Now that I have removed the images and text, I can move on to adding the thumbnails.

Using my favourite paint software I have reduced the size of each image by a ration of 4:1 to give thumbnails as shown below.

           

You will see that these images are large enough to have a resonable image quality.

To display these images I need to set them as the background image of the link surrounding the list images. This is the most complex styling of the gallery.

/* Adding the thumbnail images */
#container a.gallery, #container a.gallery:visited {
    display:block; 
    color:#000; 
    text-decoration:none; 
    border:1px solid #000; 
    margin:1px 2px 1px 2px; 
    text-align:left; 
    cursor:default;
    }
#container a.slidea {
    background:url(../images/p1_t.jpg); 
    height:93px; 
    width:60px;
    }
#container a.slideb {
    background:url(../images/p2_t.jpg); 
    height:93px; 
    width:60px;
    }
#container a.slidec {
    background:url(../images/p3_t.jpg); 
    height:93px; 
    width:60px;
    }
#container a.slided {
    background:url(../images/p4_t.jpg); 
    height:60px; 
    width:93px;
    }
* html #container a.slided {
    width:91px; 
    w\idth:93px;
    }
#container a.slidee {
    background:url(../images/p5_t.jpg); 
    height:60px; 
    width:93px;
    }
#container a.slidef {
    background:url(../images/p6_t.jpg); 
    height:60px; 
    width:93px;
    }
* html #container a.slidef {
    width:91px; 
    w\idth:93px;
    }
#container a.slideg {
    background:url(../images/p7_t.jpg); 
    height:60px; 
    width:93px;
    }
#container a.slideh {
    background:url(../images/p8_t.jpg); 
    height:93px; 
    width:60px;
    }
#container a.slidei {
    background:url(../images/p9_t.jpg); 
    height:93px; 
    width:60px;
    }
#container a.slidej {
    background:url(../images/p10_t.jpg); 
    height:93px; 
    width:60px;
    }
#container a.slidek {
    background:url(../images/p11_t.jpg); 
    height:60px; 
    width:93px;
    }
* html #container a.slidek {
    width:91px; 
    w\idth:93px;
    }
#container a.slidel {
    background:url(../images/p12_t.jpg); 
    height:60px; 
    width:93px;
    }

Example #5

This firstly adds the styling that is common to all the links using the gallery class, then styles each unique list / link item using the 'slide letter' classes.

The example now shows the thumbnails as a vertical list of links, centrally placed in Internet Explorer and left aligned in all other browsers, with a default arrow cursor instead of the usual pointer.

I have added the 1px black border to each thumbnail, the left / right 2px margin and a top / bottom margin of 1px. I have also set the text to be left aligned. This will show up later when the text is displayed 'on hover'.

Step 9

Putting the thumbnails in order

Now that I have the thumbnails displayed I can place them in the correct column / row order. Because I have already worked out the size of the thumbnails to allow either three portrait images or two landscape ones in a width of 198px, I can style the <ul> to be 198px wide. I will also have two rows of portrait and three rows of landscape thumbnails each with a 1px border and a 1px top / bottom margin which gives a vertical height of 386px. Finally to place the thumbnails inline I have added a left float to the <li>s.

So I can ADD the following to the list styling.

/* set the size of the unordered list to neatly house the thumbnails */
#container ul {
    width:198px; 
    height:386px;
    }
#container li {
    float:left;
    }

Example #6

The gallery is beginning to take shape. The thumbnails are in order but still centered in the containing box in Internet Explorer and on the left side in all other browsers.

I have chosen to move them to the right hand edge. But this could equally as well be the left hand edge. All that is needed to do this is to float the <ul> to the right (or left).

I will also give the <ul> a margin to space it away from the container border.

/* move the thumbnails into the correct position */
#container ul {
    margin:5px; 
    float:right;
    }

Example #7

The thumbnails are now in position on the right hand side of the containing div in all browsers.

The actual position from the right hand edge will vary slightly between browsers. If this matters you can add a hack to target Internet Explorer to bring it into line with other browsers, but I don't see this as a problem.

Step 10

The thumbnail :hover

All that is left to do is to add the :hover styles to the thumbnails, spans and images.

The thumbnail :hover style is a simple border color change from black to white.

/* change the thumbnail border color */
#container a.gallery:hover {
    border:1px solid #fff; 
    }

Example #8

If you now hover the mouse over the thumbnails you will see that their black borders looks as though they vanish.

Step 11

The span :hover

Next I will add the :hover span style. Because I have a relatively positioned #container div I can give the span an absolute position within this container (as I did at step 7 when hidding the images). I need to give this a width and height value of 372px to enable both portrait and landscape images to be fully displayed and a position of 10px from the top and 75px from the left to roughly center the images in the space available.

/* styling the :hover span */
#container a.gallery:hover span {
    position:absolute; 
    width:372px; 
    height:372px; 
    top:10px; 
    left:75px; 
    color:#000; 
    background:#fff;
    }

Example #9

Hovering over the thumbnails will now make the full size images appear. You will notice that the text is only visible below the landscape images. This is because the portrait images take up all the available height so the text below the images is hidden.

To overcome this I need to style the images so that the text will appear to one side when I display the portrait images. I can do this by using a left float on the :hover img style. This will have no effect on the ladscape images.

#container a.gallery:hover img {
    border:1px solid #fff; 
    float:left; 
    margin-right:5px;
    }

Example #10

The text is now shown to the right of the portrait images and below the landscape images.

Step 12

A few extra bits of styling

I could if I wish leave the styling as it is, but with just a little bit of extra styling I can improve the look and give a bit more variety to the gallery. I can easily style the middle portrait images to float right within their <span>s so that the text will then appear on the left.

#container a.slideb:hover img, #container a.slidei:hover img {
    float:right;
    }

Example #11

The images of MINIE and the WESTY PUP are now positioned to the right of their <span> containers and the text is to the left.

And finally..

When no images are displayed I am left with an uninteresting blank area on the screen. This would look better if I had a default image with perhaps a gallery title displayed. I can do this by adding a background image to the #container div and, if this image is located in the same area as the span :hover, it will be hidden when I hover over a thumbnail images.

I have created the following image for this purpose.

To add this to the #container style I need the following.

#container {
    background:#fff url(../images/back.jpg) 75px 10px no-repeat;
    }

Example #12

I now have the finished version of my photograph gallery.

I hope that you have been able to follow this tutorial and that you will be tempted to give it a try. Don't be afraid to experiment with the layout making sure that you understand each step before you do so, but remember that planning the layout is half the battle.