Custom Image Bullets for Unordered Lists using CSS

Unordered lists <ul> have become quite a staple in the modern web developer’s tool box. We’ve taken them quite far with fancy menus and the like. However, we seem to forget about styling good ‘ol lists! While we often put basic lists onto our sites, they do sometimes get a bit bland and it would be nice to spice them up a bit. Well here comes your guide to making your lists a bit more visually stimulating using a little css.

Example 0 (the pre basic)

Before we start getting fancy with replacing our bullets with images, let me show you what you can do using only css changes. There is a nice property in css called list-style-type which can be used on unordered <ul> and ordered <ol> lists. There are a number of declarations available with a range of browser compatibility.

View Example 0 Demo »

HTML

1
2
3
4
5
6
7
<ul>
    <li>Lorem ipsum dolor sit amet</li>
    <li>Consectetuer adipiscing elit. Etiam sollicitudin</li>
    <li>Capibus velit. Praesent eget dui.</li>
    <li>Duis non elit et massa ultrices vehicula.</li>
    <li>Aliquam fermentum ipsum auctor enim.</li>
</ul>

CSS

1
2
3
ul {
    list-style-type:square;
}

Example 1 (the basic)

OK, so now you’re (sarcastically) thinking “Wow Jesse, you turned the circle bullet into a square!”. Yea, I know that wasn’t too exciting, the good stuff is on the way. I just thought it would be nice for you to be fully versed in the bullet options (Hey I called it “Example 0” didn’t I?). Now, when following the links above you may have ran across another css declaration called list-style-image. In theory this is used to do what we are trying to accomplish here: Replace the bullet with a custom image. However, in practice this CSS declaration does not work dependably across browsers. Particularly regarding exact position of the bullet image. That being said we will not be using this declaration, instead will be putting the image onto the <li> using the background: property.

View Example 1 Demo »

CSS

1
2
3
4
5
6
7
8
9
10
11
ul{
    list-style:none;
    margin:0 0 1em 15px;
    padding: 0;
}
ul li{
    line-height:1.3em;
    margin: .25em 0;
    padding: 0 0 0 15px;
    background:url(scho-arrow.gif) no-repeat 0 7px;
}

Custom Image Bullets - diagram

Now to explain the CSS a bit. First the <ul>. We remove the bullets with list-style:none;. Next we set the margin. We remove any default margins set by the browsers, set the left margin to 15px to indent the list, and set the bottom margin to 1em to offset the entire list from the content that follows it on the page. We do this by using the CSS shorthand margin:[top] [right] [bottom] [left];. We then set padding:0; to remove any default padding set by the browsers.

Next we adjust the <li>. We set the line-height:1.3em; to give the text some vertical spacing. We then set the top and bottom margin to .25em to give the line items a bit of vertical spacing and the left and right margin to 0 to reset any defaults set by the browsers. Next, we set the padding using shorthand like we did with the margin. We set the top, right and bottom paddings to 0 and then set the left to 15px. This 15px of <li> padding intents the text to make room for the image. You will want to adjust this to a couple px more than the width of your bullet image to make room for the image and give a little extra space before the text starts. Now to keep a uniform indent, I suggest keeping the total of the padding-left of the <li> and the margin-left of the <ul> to 30px. So if you have a smaller image you may end up setting the <li> padding-left to 10px and then setting the <ul> margin-left to 20px. This keeps the text indented 30px from the left side. Finally, we declare the background using the following CSS shorthand: background:[image url] [repeat] [image left pos] [image top pos]; Here you see we’ve declared the background-image, set it to no-repeat, set the left postion to 0 and then the top position to 7px. Now, depending on the height of your bullet image and the size of your text,  you’ll likely want to adjust this top positioning to vertically center your image on the text.

Example 2 (adding polish)

Example 1 got us rolling with the basic idea, but has a few minor issues to work out. First of all, since we set margin-bottom:1em; on the <ul> it causes nested lists to have too much space between the end of a 2nd level list and the next line item of the 1st level list. To fix that, we need to set bottom-margin:0; to all <ul> inside of <li>. Next, there is a small bug that plagues (you guessed it) IE 6 regarding background images that we apply the holly hack to fix. In this example, I’ve added a 2nd level list and a really long <li>. By doing this, you can see why we set the line-height and the top and bottom margin on the <li> in Example 1. Notice how the <li> that wraps still has spacing above and below it to separate it from the surrounding line items? That’s the top and bottom margin at work.

View Example 2 Demo »

CSS – Added

1
2
3
4
5
6
7
li ul{
    margin-bottom:0;
}
/* Holly Hack to fix ie6 li bg */
/* Hides from IE-mac \*/
* html li{height: 1%;}
/* End hide from IE-mac */

Example 3 (real world example)

Now that you’ve got the idea, I’m going to show you a real world example where we tweak a couple things. First, we’re going to set the 2nd level lists back to bullets instead of images. Then we’re going to drop in some print styles so that when the page is printed it shows the default bullets.  We’re doing this because most browsers do not print background images by default and our custom bullets are background images! (Try a Print Preview of Example 3 on your browser to check it out.)

View Example 3 Demo »

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ul{
    list-style:none;
    margin:0 0 1em 15px;
    padding: 0;
}
ul li{
    line-height:1.3em;
    margin: .25em 0;
    padding: 0 0 0 15px;
    background:url(scho-arrow.gif) no-repeat 0 4px;
}
li ul{
    margin:0 0 0 30px;
    list-style:disc;
}
li ul li{
    padding-left:0;
    background:none;
}

/* Holly Hack to fix ie6 li bg */
/*  Hides from IE-mac \*/
* html li{height: 1%;}
/* End hide from IE-mac */

@media print{
ul {
    list-style:disc;
    margin-left:30px;
}
ul li {
    padding-left:0px;
    background:none;
}
} /* end print */

Example 4 (getting creative)

Once you get the hang of this the possibilities are really endless. In this final example I’ll throw a few more styles in there to show you what we could do with a “Yes/No” type of list. I’ve defaulted the list items to “Yes”, but then added a class="no" to <li> that I want to have the “No” look. This could be used in a list of product features etc. To keep the usability, I’ve even set the print styles to an open circle for the “No” items and filled circle for the “Yes”. (yes/no icons from sweetie)

View Example 4 Demo »