This article
originally appeared in the Design & Usability Tactics newsletter. Click
here
to subscribe automatically.

When you’re working with CSS,
sometimes the obvious technique doesn’t produce the effect you might expect or
desire. Fortunately, there’s a good chance that you can achieve the effect you
want if you’re willing to look beyond the obvious and try other methods. I
encountered this exact situation recently when looking for a way to add an icon
beside each item in a list of links, as shown in Figure A.

Problems with the obvious solution

Since the links are normally marked
up as an unordered list, it seems obvious to replace the default bullet
preceding each list item with an image file for the desired icon. All you need
to do is create a style to specify the list-style-image
attribute. If each list item contains a separate id, you can create a separate
style for each id so that each item has a different icon.

The technique is simple, and it sort
of works, as you can see in Figure B.
There are some alignment issues if the icon is taller than the text (as in this
example), but the real problem is that the icon isn’t a clickable part of the
link because the bullet is in a separate box from the list item’s text.

Most visitors wouldn’t notice
whether the bullets beside a list of links are clickable, but icons are
different. The icons look a lot like buttons, so visitors will probably try to
click them; therefore, it will confuse and disappoint users if clicking the
icon doesn’t work just like clicking the text portion of the link.

After spending time trying to extend
the clickable area of the link over the bullet/icon, I became frustrated with
the list-style attributes’ limitations and started looking for alternatives. I
found some references to creating bullets with more flexible positioning
options using display marker.
However, since the dominant browser doesn’t support that particular part of the
CSS specification, it’s not a practical solution. (Maybe someday we’ll be able
to use all of the tools CSS provides, but that day isn’t here yet.)

An alternative that works

When the obvious solution to a
problem doesn’t work, it’s time to look for other approaches. An article
by Dan Cederholm
of Simple Bits provided me with an alternative approach to
this particular challenge.

His technique puts the icon into the
background image of each list item instead of adding the icons as bullets. It’s
basically the same technique that is used for creating hybrid graphical/text
buttons that employ CSS-styled text over a background image of a button.

The difference is that the icon
image doesn’t fill the entire background of the list item. Instead, it sits at
the left edge of the list item’s box, and a padding attribute pushes the text
of the list items over to the right, past the icon image. The effect is
visually the same as the icons floating to the left of the list items, but the
icons are within each list item’s box, and you can use display:block to make the entire box clickable. This solves the
problem of the unclickable icon.

The following code creates the
effect that you see in Figure A. The markup is
simply an unordered list of links, each with a separate id attribute.

<div id="linklist">
    <ul>
        <li id="check"><a href="link1A.html">Link 1</a></li>
        <li id="asterisk"><a href="link2A.html">Link 2</a></li>
        <li id="x"><a href="link3A.html">Link 3</a></li>
    </ul>
</div>

Here’s the CSS that makes it work:

div#linklist {
    margin-left: 50px;
}
div#linklist ul {
    margin:0;
    padding:0;
    list-style-type: none;
}
div#linklist li {
    height:38px;
    width:100px;
    background-position:left;
    background-repeat:no-repeat;
    line-height: 38px;
    margin-bottom:10px;
}
div#linklist li a {
    height: 100%;
    width: 100%;
    display: block;
    padding-left: 45px;
    text-decoration: none;
}
div#linklist li a:link {
    font-weight: bold;
    color: #000000;
}
div#linklist li a:visited {
    font-weight: normal;
    color: #999999;
}
div#linklist li a:hover {
    font-weight: bold;
    color: #0000FF;
}
div#linklist li a:active {
    font-weight: bold;
    color: #CC0033;
}
div#linklist li#asterisk {
    background-image:url(asterisk.jpg);
}
div#linklist li#check {
    background-image:url(check.jpg);
}
div#linklist li#x {
    background-image:url(x.jpg);
}

Deconstructing the code

The div#linklist ul style zeros out the default margins and removes the
default bullets normally associated with an unordered list. The div#linklist li style defines the size
of the list item box (height:38px and
width:100px), positions the
background image at the left end of that box (background-position:left;), and sets the background image to show
only one copy of the image (background-repeat:no-repeat;).
In addition, the line-height:38px
rule centers the text vertically within the box, and the margin-bottom:10px rule adds a little space between icons.

The div#linklist li a style makes the entire box clickable (height:100%; width:100%; display:block;)
and removes the underline from the links (text-decoration:none;).
This is also the home of the padding-left:45px
rule, which pushes the text over to the right of the icon. It’s important to
note that the padding-left rule is
part of the style for the div#linklist li
a
selector instead of the div#linklist
li
selector. Otherwise, text within the <a> tag would revert to its
normal position.

The styles for the various link
pseudoclasses (div#linklist li a:link,
etc.) set the text formatting for the corresponding link states. This is the
normal text rollover effect and doesn’t really affect icon placement or
clickability.

Finally, the styles for each of the
named list items (div#linklist li#check,
etc.) set the background images to use as icons for the corresponding links. If
you want to use the same icon for all the list items, you could put the background-image:url(check.jpg); rule in
the div#linklist li style instead of
creating separate styles for each item.

Note: For the sake of
clarity, this example code uses long selectors to produce maximum specificity.
In most cases, you could shorten a selector such as div#linklist li#check to become #check.
The resulting style sheet would be smaller and work just as well.