Deferred font loading and using localStorage as cache

The idea is to lazy-load web fonts once everything else loaded completely, store them in localStorage to be used for subsequent pages. A cookie is used as a flag to check if the fonts are cached in localStorage.

There are something to note:

  • If visitors disable cookie, this method will backfire as the webfont will be reloaded everytime visitors go to a different page.

  • localStorage is slower than browser cache (So i heard).

  • A browser that supports localStorage is required, which mean IE8+, Firefox, Opera and Chrome.

  • On first load, the page will be flashed a bit after finish loading web fonts. This happened because the web fonts finish loading and are re-applied onto the page. Because of this particular reason, I refuse to use this method to lazy-load web fonts. I just hate it seeing it flashed. I’m a sucker for this kind of detail.

  (function () {
    "use strict";
    // once cached, the css file is stored on the client forever unless
    // the URL below is changed. Any change will invalidate the cache
    var css_href = './index_files/web-fonts.css';
    // a simple event handler wrapper
    function on(el, ev, callback) {
      if (el.addEventListener) {
        el.addEventListener(ev, callback, false);
      } else if (el.attachEvent) {
        el.attachEvent("on" + ev, callback);
    // if we have the fonts in localStorage or if we've cached them using the native batrowser cache
    if ((window.localStorage && localStorage.font_css_cache) || document.cookie.indexOf('font_css_cache') > -1){
      // just use the cached version
    } else {
     // otherwise, don't block the loading of the page; wait until it's done.
      on(window, "load", injectFontsStylesheet);
    // quick way to determine whether a css file has been cached locally
    function fileIsCached(href) {
      return window.localStorage && localStorage.font_css_cache && (localStorage.font_css_cache_file === href);

    // time to get the actual css file
    function injectFontsStylesheet() {
     // if this is an older browser
      if (!window.localStorage || !window.XMLHttpRequest) {
        var stylesheet = document.createElement('link');
        stylesheet.href = css_href;
        stylesheet.rel = 'stylesheet';
        stylesheet.type = 'text/css';
        // just use the native browser cache
        // this requires a good expires header on the server
        document.cookie = "font_css_cache";
      // if this isn't an old browser
      } else {
         // use the cached version if we already have it
        if (fileIsCached(css_href)) {
        // otherwise, load it with ajax
        } else {
          var xhr = new XMLHttpRequest();
"GET", css_href, true);
          // cater for IE8 which does not support addEventListener or attachEvent on XMLHttpRequest
          xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
              // once we have the content, quickly inject the css rules
              // and cache the text content for further use
              // notice that this overwrites anything that might have already been previously cached
              localStorage.font_css_cache = xhr.responseText;
              localStorage.font_css_cache_file = css_href;

    // this is the simple utitily that injects the cached or loaded css text
    function injectRawStyle(text) {
      var style = document.createElement('style');
      // cater for IE8 which doesn't support style.innerHTML
      style.setAttribute("type", "text/css");
      if (style.styleSheet) {
          style.styleSheet.cssText = text;
      } else {
          style.innerHTML = text;


I did not write this code. This bit was taken from Smashing Magazine - source. {: .alert .alert-info}