This is a CSS tutorial on how I created the image browser controls for Shacknews. The new screenshot gallery needed a custom navigation system to allow the user to get around. The most challenging part of the project was coming up with an unobtrusive way to allow the user to move backwards or forwards in a set of images, then making it work reasonably well in most modern browsers. I came up with this technique using nothing but CSS and images. No Javascript.1
Look at some screenshots on Shacknews to see how this concept works in the wild. I've cleaned up and modified the CSS from the original,2 but the underlying concept is the same. This technique can be easily integrated into a full-fledged gallery browser like you see on Shacknews, or into a fancy AJAX image browser, but those things are beyond the scope of this tutorial. I'm only concerned with the arrows, and as such, the demo above is just a single image.
This tutorial assumes a working knowledge of CSS image replacement and a few CSS filters.
The HTML is very basic. div.shot contains the Previous/Next controls and the linked image itself. The controls are standard text links.
The links were changed to point to # for readability.
<div class="shot">
<div class="controls">
<a class="previous" href="#prev" title="Previous">Previous</a>
<a class="next" href="#next" title="Next">Next</a>
</div>
<a href="#download"><img src="baseballws.jpg" title="Download" alt="Download"/></a>
</div>
div.shot is given a relative position so the controls can later be absolutely positioned inside it. Its overflow is set to hidden to keep the controls from extending outside the image.
IE 5.x will extend the controls below the image, so a workaround is put in place here. Using the * html CSS hack, which only works with IE 6 and lower, div.shot is floated to the left. This removes div.shot from the document flow which prevents IE 5.x from extending the controls outside the image into the content area.
div.shot {
position: relative;
overflow: hidden;
}
* html div.shot {
float: left;
}
The link text is hidden and the link outline is removed.3 The controls are absolutely positioned at the top left and top right of div.shot. They are given a width of 45% to allow for a gutter in the center of the image where the user can rest the mouse without having an arrow blocking their view. They can also use this gutter to click on the image itself. The blue areas in the image to the right represent the controls. The stripe down the center is the gutter.
We shouldn't have to set the background-image for the controls at this point. Logically, the background-image should be left blank in its default state, then set to an arrow when the user hovers over the control area. However, IE doesn't recognize the controls on top of the linked image unless you give the them a background of some sort, so we're forced to set the arrow images here. To counter-act this, the controls are made invisible by setting the opacity to 0.4
The height of the controls is set to 100%, which means 100% of their container, div.shot, whose height is determined by the image. However, IE thinks 100% means the height of a line of text. See the image to the right. To get around this, the height of the controls must be set manually in IE. I chose a huge number, 10000px, which should cover even the tallest images.5 Since div.shot's overflow property is set to hidden, the controls are clipped at the bottom of the image.
The arrows should be vertically centered in the image. Setting background-position to center center is good enough for most browsers because the height of the controls is determined by the height of the image. However, because we had to manually set the height of the controls to 10000px in IE, the vertical centers of the controls in that browser are 5000px - way past the bottom for most images. To remedy this, the background-position is set to center 150px in IE. Sadly, this means the arrow won't be vertically centered in that browser. 150px looks pretty good for the demo image, but if your site's images are taller or shorter on average, you can adjust the number to suit your needs.
div.controls a {
text-indent: -5000px;
overflow: hidden;
outline: none;
position: absolute;
top: 0;
right: 0;
width: 45%;
height: 100%;
background-position: center center;
background-repeat: no-repeat;
background-image: url(bg-next.gif);
opacity: 0;
filter: alpha(opacity=0);
}
* html div.controls a {
height: 10000px;
background-position: center 150px;
}
div.controls a.previous {
left: 0;
background-image: url(bg-previous.gif);
}
For cases where the user is on the first or last image in a set, an alone class is available. For the first image in a set, there would be no a.previous. If you give a.next an additional class of alone, the control will take up most of the image and the gutters would be on the sides. The image to the right shows the area a.alone covers.6
To complete the effect, when the user hovers over a control the opacity is bumped up to 0.25. At this opacity value, the user can see the control but it's not overpowering. Adjust to your liking.
div.controls a.alone {
width: 90%;
margin: 0 5%;
}
div.controls a:hover {
opacity: 0.25;
filter: alpha(opacity=25);
}
outline gets rid of the bug.opacity property, so a IE-proprietary filter is used to accomplish the same thing.alone control would look like this.
<div class="shot">
<div class="controls">
<a class="next alone" href="#" title="Next">Next</a>
</div>
<a href="#"><img src="baseballws.jpg" title="Download" alt="Download"/></a>
</div>
As far as I know, this technique works in Firefox, IE 5.01, IE 5.5, IE 6, IE 7, Opera 9, and Safari 3 Windows. Opera 8 and under are known to fail since they lack CSS opacity support. Mac browsers are untested. Someone buy me a Mac.
Photo by Janessa White.
If you have any questions or comments, send me a note.
Last updated August 24, 2007