Mobile connections aren’t as good as the usual desktop ones, therefore the download time of custom fonts can take up to several seconds. A good approach is to use the @font-face rule only for certain range of media and screens using @media queries. Unfortunately this approach doesn’t work for some browsers: all the versions of Internet Explorer and FireFox 10 and lower. This article discusses a solution for this problem that balances performances and hacks.

MAJOR UPDATE: With certain constraints, a better approach than the one discussed in this article exists. More info here

What’s the Problem?

When I started creating my new website, I wanted to create a strongly mobile optimized design having also in mind the achievement of high performances. One of the thing I really wanted to avoid was the effect, seen on several websites when I access them through my smartphone, of a white block where it’s supposed to be the content. This issue is caused by a custom font, applied to the text, that it isn’t completely loaded as shown in the image below.

A page with custom font not completely downloaded

So, what’s the solution? A good approach is to apply a custom font, using the @font-face rule, only for certain range of media and screens, using @media queries. You might think that the best solution would be to apply the custom font only to those users visiting the website with a fast connection, and you’re absolutely right. Unfortunately there isn’t yet such a system although it has been discussed several times on the WHATWG mailing list.

@font-face inside a @media query

To better explain the solution, we’ll create two files: index.html and style.css. The first is the ideal page having the text with the custom font applied while the latter contains the style of the page.

An hypothetical index.html page could be the following:

<!DOCTYPE html>
<html>
   <head>
      <link rel="stylesheet" href="style.css" />
   </head>
   <body>
      <p>
         This is an amazing text because has a custom font.
      </p>
   </body>
</html>

As you can see, it’s very basic since it has only one paragraph and the link to the stylesheet.

The following, instead, is an hypothetical source for the style.css file using a mobile first approach:

p {
   font-family: Arial,Helvetica,sans-serif;
}

@media only screen and (min-width: 980px) {
   @font-face {
      font-family: "OctinSports";
      src: url("fonts/octinsports.eot");
      src: url("fonts/octinsports.eot?#iefix") format("embedded-opentype"),
      url("fonts/octinsports.woff") format("woff"),
      url("fonts/octinsports.ttf") format("truetype"),
      url("fonts/octinsports.svg#OctinSports") format("svg");
      font-weight: normal;
      font-style: normal;
   }

   p {
      font-family: "OctinSports";
   }
}

The stylesheet shown, sets for all the paragraphs an Arial font, with several fallbacks. The font stack used is composed of fonts that are really common and highly present in the major operative systems. In fact, based on CssFontStack, Arial achieve the 99.84% on Windows and the 98.74% on Mac. In case none of the selected fonts is available, the CSS asks for a generic sans-serif font.

The second part of style.css specifies the media query. With it, we’re targeting all the devices that have a screen and with the screen’s width of at least 980px (you can use a different breakpoint). Inside it, we’ve the @font-face rule to download the custom font, using the Fontspring Bulletproof @Font-Face Syntax. Then, we’re simply applying the new font to all the paragraphs, overriding the previously set style.

Browsers Compatibility

This solution is really smart because it applies a custom font only for users that have a big screen and should not have problem for a little bandwidth overhead. Unfortunately, this approach is not supported by Internet Explorer 10 and lower, and Firefox 10 and lower. Although you can think it’s a strange behavior, it actually comes from the CSS2.1 specifications that asserts: At-rules inside @media are invalid in CSS2.1.

So, while the last version of Internet Explorer still doesn’t support this feature, the company behind FireFox, Mozilla, added the support for versions after the 10th. Therefore, the issue is significant only for Internet Explorer. Another point to keep in mind is also that Internet Explorer 8 and lower doesn’t understand @media queries, so even if they updated new versions, the problem would remain for older ones.

How to (Partially) Solve the Problem

Is there a way to solve the problem of @font-face inside a @media query in Internet Explorer? The answer is yes, partially.

As I said in the introduction, I came across this issue during the development of my website. I wasn’t aware of the compatibility problem of Internet Explorer, so, just like every good developer, the first thing I did to understand what was going on, was to use Google. During my research, I found an article titled Do Not Put @font-face Inside @media Query that gave the answer needed on the cause, but not on the solution. Besides, the article also suggested to not have @font-face inside @media queries. I was really determined to solve the issue, so I searched a little more. Unfortunately, I didn’t succeed, so I decided to create one by myself.

Solve the Problem for Internet Explorer 9 and Lower

Based on what I described so far, the problem is relevant only for Internet Explorer, so we can try to target this specific browser. The first thing that could came to mind is to create a separate CSS file, for example fonts.css, containing all the @font-face rules, not into a @media query, and use a conditional comment. Thus, the source of fonts.css should be like this:

@font-face {
   font-family: "OctinSports";
   src: url("fonts/octinsports.eot");
   src: url("fonts/octinsports.eot?#iefix") format("embedded-opentype"),
   url("fonts/octinsports.woff") format("woff"),
   url("fonts/octinsports.ttf") format("truetype"),
   url("fonts/octinsports.svg#OctinSports") format("svg");
   font-weight: normal;
   font-style: normal;
}

Using this approach, we have the advantage of keeping the weight of the page the same as before, apart for the few bytes for the conditional comment part, for all the browsers but Internet Explorer. For the latter, instead, we’ll add also a little overhead because of the additional stylesheet to download. However, containing only the very few lines about @font-face rules, minimizing it, an average file should cause an additional weight of no more than 1-2kb, that in most cases is an acceptable compromise.

The code that implements the approach, using the minified version, is the following:

<!--[if IE]>
   <link rel="stylesheet" href="css/fonts.min.css">
<![endif]-->

This solution is simple but not definitive because, as you might know, Internet Explorer 10 dropped support for conditional comments, so this version will ignore the snippet. In conclusion, our problems aren’t ended yet.

Solve the Problem for Internet Explorer 10

To target IE10 we’ll use a less clean approach, because we need a hack, but that works fine. Specifically, the hack used is based on JavaScript and is discussed in the article IE10 CSS Hacks. What this snippet does is to detect IE10 and test if the window’s width is greater than or equal to 980px. If these conditions are true, it adds the same fonts.min.css stylesheet to the <head> element of the page. Remember that since it’s based on JavaScript, if the latter is disabled the hack won’t work.

<!--[if !IE]><!-->
   <script>
       if (Function('/*@cc_on return document.documentMode===10@*/')() && window.innerWidth >= 980) {
          var link  = document.createElement('link');
          link.rel  = 'stylesheet';
          link.href = 'css/fonts.min.css';
          document.getElementsByTagName('head')[0].appendChild(link);
       }
   </script>
<!--<![endif]-->

How this Solution Deals with a Responsive Web Design Approach?

A good question that you can arise is how this solution actually solves the responsive approach of a website. To answer this question, let’s split the discussion into two branches. The first regards mobile users where we don’t want the custom font, and the second regards desktop users where we do want the font to be applied.

Mobile Users

To start the discussion, let’s have a look at the last statistics (June 2013) about mobile browsers usage provided by StatCounter. The link gives us the following statistics:

  1. Android: 29.06%
  2. iPhone: 22.77%
  3. Opera: 16.06%
  4. UC Browser: 9.89%
  5. Nokia: 7.38%
  6. Chrome: 3.23%
  7. BlackBerry: 3.11%
  8. NetFront: 2.40%
  9. iPod Touch: 2.21%
  10. Others: 3.9%

An important important point to get from these statistics is that none of them is Internet Explorer, and that its usage has been counted in the voice “Others”. However, thanks to Craig Buckler, one of the regular and surely the most known blogger of SitePoint, I discovered that StatCounter report an usage of 1.4% for IEMobile (no distinction between versions). Therefore, having the @font-face rule inside the @media query, we’re achieving our goal of having a basic font at least for the 98.6% mobile users.

Craig also wrote me that NetMarketShare report shows 1.31% usage for IE9 and 1.0% for IE10 mobile. Of course statistics can vary a little from site to site but we got the general point.

Now, let’s take into account the two major versions of Internet Explorer for mobile: 9 and 10.

As we’ve seen in a previous section, we’re targeting IE10 using a JavaScript code that uses an hack and test for the window’s width. If the device has JavaScript enabled, being the window’s width less than 980px, the fonts.min.css stylesheet will not be added. Otherwise, if JavaScript is disabled, the snippet won’t run and the custom font won’t be loaded or set. Thus, our goal is achieved.

About IE9, there isn’t much to do: the stylesheet will be loaded and the custom font applied anyway. However, this issue should affect no more than the 50% of those using IEMobile.

To wrap up, the font is not applied in roughly the 99.5% of the cases with a fail only on IE9. A big success.

Desktop Users

As for the previous section, let’s have a look at the last statistics (June 2013) about desktop browsers usage. The desktop statistics are the following:

  • Google Chrome: 42.71%
  • Firefox: 20.01%
  • Internet Explorer 10: 9.88%
  • Safari: 8.39%
  • Internet Explorer 8: 8.04%
  • Internet Explorer 9: 6.79%
  • Opera: 1.03%
  • Internet Explorer 7: 0.49%
  • Internet Explorer 6: 0.22%
  • Others: 2.44%

Since we kept the @font-face rule inside the @media query, we’re still optimizing the website for all the browsers that do support both @media queries (not IE8 and lower) and @font-face inside @media queries. As we’ve seen, these are all the browsers but Internet Explorer. In conclusion, we’ve a proper optimization for 74.58% users. A good starting point!

For Internet Explorer 6-9, the custom font will be loaded, as we wanted, using a conditional comment. So, to the previous percentage we can add another 15.54% which lead to a partial total of 90.12%.

Regarding Internet Explorer 10, since we rely on a JavaScript method to load the stylesheet, the custom font is loaded for all those who have JavaScript enabled. I’m not able to provide any statistics on this but those with JavaScript disabled should not exceed the 0.5%.

To wrap up, the font is applied in roughly the 99.5% of the cases. Another big success.

Update Thanks to Tim Kadlec

Most browsers won’t download web fonts unless needed. This means you can declare all of your @font-face rules outside of any media queries, and then only use that font in the font-stack for certain resolutions. The exception is still IE

Following Update by Me

After his comment, I deepened a little more and found that the terms “unless needed” should be clarified. His note is true for all major browsers only if you use a mobile-first approach. In fact, if you used a desktop-first approach, all the versions of IE (IE 10 and below) aren’t able to skip the download of a font, even if it won’t be really used. So, if you have in your stylesheet a code like this:

@font-face {
  font-family: "some-font";
}

/* DESKTOP-FIRST APPROACH */
div {
    font-family: "some-font";
}

@media screen and (max-width: 768px) {
    div {
        font-family: Calibri;
    }
}

And you’re viewing the page from a device with a screen resolution equal to or less than 768px using a browser like Google Chrome, FireFox and others, the custom font won’t be downloaded because it isn’t really used, as shown by the following screenshot:

Chrome does not load font for mobile

On the contrary, Internet Explorer will download it anyway, as shown by the following screenshot:

IE loads font for mobile

As you can see, both the screenshots are in Italian but you can easily understand that while Chrome downloads just the page, IE downloads the page and the font.

Final Notes

To wrap-up, if your website already uses a mobile-first approach, follow the Tim Kadlec’s suggestion. Otherwise, if you’re using a desktop-first approach and don’t want to make heavy changes, you can follow the method explained in this article.

In case you want to play with the demo I created to test the behavior I described, you can download the font-face demo here.

Conclusions

Custom fonts can give a nice look to a website and more and more developers and designers are using them. However, we don’t have to forget to optimize for mobile devices due to the increasing traffic coming from them. As we’ve seen in this article, using a mobile first approach for web fonts having @font-face inside @media queries, together with the use of a couple of tricks that target Internet Explorer, is possible to achieve both the goals. We can trust this technique because they’re safe and let us achieve a really high success percentages: 99.5% both for mobile users and desktop users.

How to Solve the Problem of @font-face Inside Media Queries
Tagged on: