Grow your CSS skills. Land your dream job.

Favicons Next To External Links

Published by Chris Coyier

I've had this JSFiddle from CSS Wizardry open for like 2 weeks in my browser. I kept thinking about it, because before that I got an email from someone asking about essentially the same thing and it stuck in my head. They were wanting to insert a favicon next to links and use only CSS to do it. Unfortunately I haven't found a way to do exactly that, but using some jQuery we can do it pretty easily.

The "I Wish" CSS Only Technique

What would be nice is if you had simple semantic HTML like this:

<a href="http://github.com">GitHub</a>

And then you could access everything you needed to insert a background image of the favicon using a service like getFavicon.

/* Fair warning, this doesn't work */

a[href^="http"]:before {
  content: url(http://g.etfv.co/ + attr(href) + );
}

Maybe the syntax wouldn't be exactly like that, but something like it. The point is, you can't mix up the url() syntax into parts like that in CSS.

Google's Favicon Service

Google has it's own favicon service you can use. For example:

http://www.google.com/s2/u/0/favicons?domain=css-tricks.com

The trick is you need just the host name and TLD and nothing else. I searched around and found a simple regex for getting that from any URL. We'll need that because links aren't always (or even usually) the root of sites.

function getDomain(url) {
   return url.match(/:\/\/(.[^/]+)/)[1];
}

Using these things, and jQuery, we'll find all links and apply the favicon as a background image. The external link checking is pretty rudimentary, but there are more robust methods here if need be.

$("a[href^='http']").each(function() {
    $(this).css({
        background: "url(http://www.google.com/s2/u/0/favicons?domain=" + getDomain(this.href) + 
        ") left center no-repeat",
        "padding-left": "20px"
    });    
});

Then @travis reminded me that you can just use this.hostname instead of the fancy regex. So:

/* Nothing else needed */
$("a[href^='http']").each(function() {
    $(this).css({
        background: "url(http://www.google.com/s2/u/0/favicons?domain=" + this.hostname + 
        ") left center no-repeat",
        "padding-left": "20px"
    });    
});

I'm not sure what the browser support is for hostname, whether it's just as good as href or less so, not sure.

getFavicon Method

@seanodotcom showed me another similar service galled getFavicon. It's hosted by Google AppEngine, but it's not Google's own service. I did find it a bit slower. But the advantage being that you don't need to deal with host names at all, you just give them the full URL.

So then it becomes:

$("a[href^='http']").each(function() {
    $(this).css({
        background: "url(http://g.etfv.co/" + this.href + ") left center no-repeat",
        "padding-left": "20px"
    });
});​

View Demo

Performance?

As I'm sure you know, the number of HTTP requests a page makes is a huge deal in performance. Each little image in these techniques are one page request each.

@yuritkanchenko pointed out to me a cool favicon service that can automatically sprite the favicons for you so you can keep it to one request.

For instance:

http://favicon.yandex.net/favicon/google.com/yandex.ru/css-tricks.com

I'm afraid I didn't go the extra mile here and write the JavaScript needed to find all links, concatenate the domains, make the request, and then apply the images as a sprite, but I'm sure you could whip that up pretty quick if you really needed it.

Comments

  1. Wouter J

    The CSS Values and Units Module Level 3 specifications describeds that this should work:

    In CSS2.1, the ‘attr()’ expression always returns a string. In CSS3, the ‘attr()’ expression can return many different types.
    (…)
    url
    The attribute value will be interpreted as the argument of a ‘url()’ expression.

    (source)

  2. Julian Cizmic

    Huh. Didn’t even know that favicon services even existed. I could imagine this being put into use, especially with favicons becoming the “identity” of a website, more or less.

  3. +1 for the “I Wish” CSS Only Technique. I wish this was true…

    I actually tried a similar approach these days and I also ended up using a jQuery solution.

  4. I was discussing exactly this with Lea Verou back in April, too bad no browser implements Level 3 attributes yet

    http://twitter.theinfo.org/192968593087004675

  5. Because you’re loading the favicons with JS, the extra HTTP hits shouldn’t be that big of deal, right? It all happens after page load.

  6. Dave

    @Aaron: It happens after document.ready, but images and whatnot will still be loading, and it would be nice if they all popped in at once!

  7. haha, pretty fun. Spent about 5 minutes mocking something stupid up.

    http://jsfiddle.net/95A4h/

    • I quite like this solution, although one tip would be to adjust the selector (at the top of the JS) so that it only selects HREFs that are to domains other than the domain we are on, or to only select HREFs that have a corresponding target=”_blank”…

      There’s no point in favicon’ing internal links in our own site! :)

    • theres a few other things that should be added if you actually wanted to use this in production.

      – remove duplicate domains from array
      – sort them then generate the background url

      this way it wouldn’t have to load multiple favicons for the same domain, and it would be able to cache the generated sprite :)

    • here You go:

      http://jsfiddle.net/95A4h/20/

      changes:
      1. favicons for links, so there’s no need to pass initial selector to links
      2. added container selector, in case You want to apply it only to one container
      3. used $.map in favor of $.each

    • rick

      you’ll also need to break it up into separate requests for a large number of links, too many will give you a 414 Request-URI Too Large

    • true, but only if the list of unique domains/pages ( different pages could have different favicons )

      played around a little and it hit me – why do we have to inline-style every single link with the same repeating css rule? why not create some kind of small style manager that would create a class, inject it and return class name that could be applied – way cleaner, feels better

      and that’s how stylist.js was born – independent ( u can use it with every framework You like ) – 2 days work so far, already works, now working on parsing input shorthand css rules passed as string – will post results when i’m more or less done :-)

  8. Jonathan

    A solution might be to use Favatar that not only retrieves various images for the web page (apple-touch-icon, og:image etc…) but also returns them as a `data:` elements, possibly making them easier to insert via CSS.

  9. Hello.

    Chad Scira has already done, but, here is another approximation : ) (I use to show the favicon, in that way you can change the font size)

    http://jsfiddle.net/tx2z/WTAr9/225/

    Saludos!

  10. utzutz

    Greetings,

    I do not know if I get something wrong now, but what’s with simply abusing the title attribute and targetting this in css ?

    Really… can someone describe me what’s the problem here?
    I Mean simply put your favicons on your server, why need an external service for that?

    • Nick Chamberlin

      Dude… seriously? It means I save 30 seconds… That’s like saying: Why go to Burger King and spend $5.00 when you could cook the same thing(but healthier) at your house in about the same time for $1.00… every muscle I move brings me one muscle move closer to death… So basically… I don’t wanna die, that’s why this is a great idea…. Your thought process is allll outa-wack man… seriously…

      Aww sweet man I just saw your name, it’s like a ninja name, I bet you yell your own name when you fly across the room with your ninja sword, all “UTZZZUTTZZZZ!!!!” *chop*… Kill Bill style with the garden hose fountain of blood flowin’… I didn’t really get that movie though, I just wasn’t IN-to it, ya know? Maybe i’ll watch it again and see if it hits more to home now that i’m older and am married..

    • utzutz

      awesome, dud… made my day ;)

      ..and your not even far of reality. You better talk about yourself in third person, when being ninja master and son of Tonny fuckin Montana.

    • SodaPop

      The problem is load time and requests. If one were to use this with a page with many external links (Classified Ad page, for example), then they may considering using a caching technique such as using PHP to download the images once a day.

    • Good call SodaPop… Load time is everything and every millisecond matters.

  11. Greatfull discussion……….and also nice article……….I m follow this site………

  12. Re support for HTMLAnchorElement#hostname: It’s not listed in DOM2 HTML, but I tried it and found it broadly supported on desktop browsers: I tested all of these successfully:

    Recent Chrome (I don’t have older copies)
    Firefox 3.6 (and so presumably all since)
    IE6 (yes, really, and so presumably all since)
    Opera 11
    Konqueror 4.7.4
    Safari 5.1
    Midori 0.4.0

    Didn’t try mobile browsers.

  13. I really like the JSFiddle tool. Have used sqlfiddle before. Thanks for letting know the services to retrieve favicon.

  14. Great article Chris! I will defiantly be using this in my next project!

  15. Jaap

    It would be nice to be able to get the title attribute as well in cases where you have lots of links and dont want to manually add a title for each link.

    Anyone know if this is possible?

  16. Tricia

    Just wish it didn’t need jq… but very user friendly thing to do :)

  17. OpenDNS just informed me the “demo” site is a phising web site.
    Glad I didn’t got tricked through this web site to go there and get personal data mis-purposed.

  18. I did something like that, as a jQuery plugin, previously. It works with most sites since most of them already have /favicon.ico in their main directory. And performance is better, since you’re sending only one image request.

    Usage is pretty simple too, just add two lines from included gist and then add ‘fav’ class to any <a href="" /> in your code. DONE.

    http://goo.gl/Ft1dM

    I hope someone ‘ll enjoy it :)

    PS. If you find some errors feel free to comment on code on gist. Cheers!

  19. Cool, sir. I’ll try

  20. @Maurice: Does the jQuery go into the site head within the tags?

    • @Avinash: There’s plenty of possibilities. The one I use the most is keeping one file for your scripts and another just for plugins, and in that case just add first line to this file and second one where you find it suitable for rendering/downloading favicons to start.

      If you don’t want to use plugins.js file then you can put it anywhere you like: in <head> in script tags, or somewhere in your main scripts file. Just remember to run this plugin (2nd line) AFTER jQuery is loaded :)

      PS. hack if you’d like to use this script from my gist – add this to your head after jQuery. Example:
      <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"><script>
      <script src="//gist.github.com/2003935/50f1d70f8e936a4eaf9ea8608aba2022c3e2b972"><script>

  21. Julian Cizmic

    BTW, Coda 2 just came out…

  22. Beben Koben

    a[href*=”css-tricks.com”] {
    padding-left: 18px;
    background: url(http://www.google.com/s2/u/0/favicons?domain=css-tricks.com) left center no-repeat;
    }

    <a href="http://css-tricks.com/">CSS Tricks</a>

  23. "I did find it [getFavicon] a bit slower"

    I think this is because it seems to load the favicons directly while googles service seems to use a cache… My own website is currently down :( and I testet it with getFavicon and it took ages to load and then showed a placeholder. When I tried it with Googles service it didn’t take long time to load but also showed a placeholder. I think this is because Google caches the icons and I currently have searchbots forbidden in my robots.txt …

  24. Thanks, I didn’t know that favicon services existed. This is useful to know! Might use it in the future.

  25. I did a little update (made them require a class) so that you can just copy and paste :)

    http://jsfiddle.net/WTAr9/664/

  26. Thanks for this excellent Tip :) i just hope sites don’t go adding / changing to dirty icons after posting a link to them lol.

    Regards, Darren

  27. FoxRox

    That’s so nice!

  28. I like the idea! Not a bad outcome either, nice work! :)

  29. And by the way, seems like we’re forced to use “http://” in the website field in the comments – good usability would allow me to type my adress in without using “http://”. :)

  30. I must say, this is a pretty spiff CSS application.. Definitely will be using this very soon. Kubashi.

  31. I’d like to thank you for the efforts you’ve put in penning this site. I really hope to see the same high-grade content by you in the future as well. In truth, your creative writing abilities has motivated me to get my own, personal website now ;)

  32. Permalink to comment#

    Good discussion. The script load time in milliseconds is the big thing.

  33. Hello, any body know how to set the size for favicon?

    Thank you.

    • I got it.

      $(“a[href^=’http’]”).each(function() {
      $(this).css({
      background: “url(http://g.etfv.co/” + this.href + “) left center no-repeat”,
      “-webkit-background-size”: “16px”,
      “-moz-background-size”: “20px”,
      “-o-background-size”: “16px”,
      “background-size”: “20px”,
      “padding-left”: “20px”,
      “margin-left”: “10px”
      });
      });

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".