Unobtrusive, cross-browser method to add icons to links
categories: front-end development, howto, jquery
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:
$('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:
// 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:
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:
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.
The class name method
In case you were wondering ...
First, put a class name on the link:
<a href="my-word-document.doc" class="word-doc">Word Document</a>
... and then style it using CSS:
a.word-doc { padding-left: 18px; background: transparent url('word.gif') no-repeat center left; }

January 6th, 2008 at 8:48 pm
Elegant. I could see using your “taking it further” solution on E-Commerce sites that have videos and extended images for products. It would save a lot of time for merchandisers who play with the copy.
January 7th, 2008 at 6:39 am
Hey, this is pretty cool. It’s a shame pure CSS stylesheets can’t give you the flexibility this approach does. Are there any real downsides to using javascript for link icons?
January 7th, 2008 at 8:12 am
@James: There are a couple of downsides that I can think of: the fact that users without Javascript can’t see it, the weight of the Javascript (while the code to accomplish this isn’t any longer than the CSS would be, the jQuery library is bigger, and also requires another HTTP request).
That said, if you are already using jQuery on your page for something else (and more and more often, I am), that becomes less of a consideration. And there are a lot more people using IE6 than there are people without Javascript enabled, so I think the tradeoff there is fair.
January 8th, 2008 at 3:19 pm
[...] are other ways than just CSS, however. Check out this post by Rebecca Murphey, “Unobtrusive, cross-browser method to add icons to links” – using javascript to get the same [...]
February 27th, 2008 at 1:27 pm
[...] hemen denedim bir türlü olmadı sonrasıda aynı sitede bulunan linklerden uygulamanın html ve farklı örneklerine ulaştım dene dene yok olmadı sonrasında ilk yapmam gerekeni yaptım ilk sitede [...]
June 18th, 2008 at 9:22 pm
This is a great use of jQuery for a very applicable script. Kudos to you!
December 19th, 2008 at 7:26 pm
What about if you have an image as a link? Will it add the icon next to an image? I am trying to find a solution so it does not add an image next to images that are links.
Thanks and great code!
December 19th, 2008 at 8:23 pm
@Aaron: after you’ve set $a, you can do:
if ($a.children(’img’).size()) { return; }
This will prevent the rest of the function from running, so the background image won’t be added.
December 31st, 2008 at 4:35 pm
This is a great use of JQuery.
How would one go about getting this to work for mailto links?
Thanks!
March 19th, 2009 at 11:58 am
[...] Wie üblich funktioniert das im IE6 nicht, es gibt aber Crossbrowser-taugliche Möglichkeit beispielsweise via jQuery. Interessierte finden dazu einen Artikel bei Rebecca Murphey. [...]
October 31st, 2009 at 9:36 am
Tanks a lot for this great tutorial! I just discovered a little bug: If a link includes a line break, the position of the inserted icon is wrong. In the pure CSS version (for all browsers, except IE 6) this does not happen.
This is how it looks on a test page: http://www.michael-van-laar.de/fileserver/diverses/icon-bug.png (Picture 1: CSS method in Firefox; picture 2: Javascript method in IE 6)
Since I’m not very familiar with Javascript yet, I don’t have an idea, if and how this could be fixed. Any ideas?