Adventures in JavaScript Development

Unobtrusive, Cross-browser Method to Add Icons to Links

| Comments

There are lots of examples of using CSS to add filetype icons to links, but they all rely on advanced CSS selectors, which Internet Explorer 6 doesn’t support.

If you’re looking for a cross-browser method of adding filetype icons to links, you have a couple of choices: you can add a class name to all of your links and target that class name with CSS that IE6 can understand; or you can let Javascript add the links dynamically based on the extension it finds at the end of each URL. The class name method is fine if you don’t mind adding the class to all of your links in your HTML, but the Javascript method will figure out which links get which icon automatically.

The Javascript/jQuery method

This uses my favorite Javascript library, jQuery; you’ll need to include the library in your document, and then either put the icon-adding code in another file you include, or put it inline with your HTML. It’s good practice to put all your jQuery code inside $.ready(), to be executed when the document is ready to be manipulated, but I’ve left that part out here for brevity.

Round 1: Because jQuery supports CSS1-3, you can mimic the CSS rule that wouldn’t work in IE6:

1
2
3
4
5
6
7
8
$('a[href$=".doc"]').
  css({
    // use paddingLeft instead of padding-left;
    // jQuery (and Javascript) use camelCase
    // for CSS attributes instead of hyphenation
    paddingLeft: '18px',
    background: 'transparent url("word-doc.gif") no-repeat center left'
  });

Round 2: You could do one of these snippets for each file type, but with jQuery, you can take advantage of the $.each() utility method to do a loop, eliminating redundant code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// first, create an object
// that contains information
// about how file extensions
// correspond to images

var fileTypes = {
  // extension: 'image file'
  doc: 'doc.gif',
  xls: 'xls.gif',
  pdf: 'pdf.gif'
};

// then, loop over the object
// using jQuery's $.each()
$.each(fileTypes, function(extension,image) {
  $('a[href$="' + extension + '"]').
    css({
      paddingLeft: '18px',
      background: 'transparent url("' + image + '") no-repeat center left'
    });
});

Round 3: One problem with this: while jQuery does support these attribute selectors, in my experience they require some pretty heavy lifting to do the pattern matching, which can slow things down significantly. Since the method above would require multiple selections (one for each extension/image combination), it makes sense to try a different way that will require fewer selections and less pattern matching:

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
var fileTypes = {
  doc: 'doc.gif',
  xls: 'xls.gif',
  pdf: 'pdf.gif'
};

// this is like $.each() above, except
// it iterates over the matched elements
$('a').each(function() {

  // get a jQuery object for each anchor found
  var $a = $(this);

  // get the href attribute
  var href = $a.attr('href');

  // get the extension from the href
  var hrefArray = href.split('.');
  var extension = hrefArray[hrefArray.length - 1];

  var image = fileTypes[extension];

  if (image) {
    $a.css({
      paddingLeft: '18px',
      background: 'transparent url("' + image + '") no-repeat center left'
    });
  }

});

And in fact, in limited testing using Firebug, this second version is faster than the first if you have more than two filetypes (and thus more than two selections).

Taking it further

You can also add a different icon to external links, and only add filetype icons to internal links:

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
var fileTypes = {
  doc: 'doc.gif',
  xls: 'xls.gif',
  pdf: 'pdf.gif'
};

$('a').each(function() {

  var $a = $(this);
  var href = $a.attr('href');

  if (
    (href.match(/^http/)) &&
    (! href.match(document.domain))
  ) {

    // use a special image for external links
    var image = 'external.gif';

  } else {
    // get the extension from the href
    var hrefArray = href.split('.');
    var extension = hrefArray[hrefArray.length - 1];

    var image = fileTypes[extension];
  }

  if (image) {
    $a.css({
      paddingLeft: '18px',
      background: 'transparent url("' + image + '") no-repeat center left'
    });
  }

});

Or, only add icons to certain links, like a list of files in an unordered list, by changing your selector from $('a') to $('ul#fileList a').

Resources

  • There are nuances to the CSS you’ll want to apply to your links; the above is just an example of something that may or may not work for you. Read more here about how to style the links so your background images appear as you want them to.
  • If you’re using transparent PNGs for your background images, iepngfix will save the day.
  • famfamfam has some great icons available for free under the Creative Commons Attribution 2.5 License.

Comments