How to use @font-face to avoid faux-italic and bold browser styles

Did you know that if you declare a custom font using @font-face, the browser will try to fake the bold and italic styles if it can’t find them? This is a clever little feature that avoids a scenario where a themer specifies a font and is then confused that bold and italics don’t work, but it can be very confusing if you actually have a bold or italic version of the font. In this article, I’ll walk you through how to properly load your font files to avoid the browser’s faux-italic and faux-bold styles.

(If you’re not interested in an explanation of the problem or the bad solution recommended by most font-embedding services, go ahead and skip down to The Right Solution.)

The Problem

First, to clarify: A font is a file containing a particular typeface, which is a particular weight or style of a type family. eg, garamond-bold.ttf is the font copy of Garamond Bold, a typeface from the Garamond family. In CSS terms, you load a font file using @font-face declarations, which append that font to a font-family.

The problem, as you can see in this screenshot, is that if you only load one font into the family, then the browser doesn’t know what to do when it’s asked to render a bold or italic section using that font. It solves this by creating a faux-bold style by stretching the letters horizontally, and a faux-italic style by slanting the letters.

comparing the browser's faux italic and bold styles to the true fonts

fig a: comparison of faux browser styles and true typefaces

The browser’s brute-force approach to creating these faux styles leaves a lot to be desired. In particular, note the proper italic font includes a variant lowercase ‘a’ without the ascender, and bold characters have an even thickness to the stroke, rather than the wider vertical strokes on the faux-bold.

The Wrong Solution

The common technique shared by many font services like FontSquirrel or WebINK is to create additional @font-face declarations, creating a new font-family definition for each font weight and style. Then you apply the regular font to the target, and write rules to apply the bold or italic fonts on any nested elements, like so:

@font-face {
	font-family: 'UbuntuRegular';
	src: url('Ubuntu-R-webfont.eot');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'UbuntuItalic';
	src: url('Ubuntu-I-webfont.eot');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'UbuntuBold';
	src: url('Ubuntu-B-webfont.eot');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'UbuntuBoldItalic';
	src: url('Ubuntu-BI-webfont.eot');
	font-weight: normal;
	font-style: normal;
}
.test {
	font-family: UbuntuRegular, arial, sans-serif;
}
.test em {
	font-family: UbuntuItalic, arial, sans-serif;
}
.test strong {
	font-family: UbuntuBold, arial, sans-serif;
}
.test strong em {
	font-family: UbuntuBoldItalic, arial, sans-serif;
}

However, doing that actually results in what you see here, where the browser still applies its own faux bold and italic styles on top of the hard-coded bold and italic fonts you defined.

double-italic and bold styles

fig b: faux browser styles applied on top of proper italic and bold fonts

To solve that problem, you reset font-weight and font-style on the nested styles to disable the faux browser styles.

.test {
	font-family: UbuntuRegular, arial, sans-serif;
}
.test em {
	font-family: UbuntuItalic, arial, sans-serif;
	font-style: normal;
}
.test strong {
	font-family: UbuntuBold, arial, sans-serif;
	font-weight: normal;
}
.test strong em {
	font-family: UbuntuBoldItalic, arial, sans-serif;
	font-style: normal;
	font-weight: normal;
}

And it seems to work perfectly! Your custom bold and italic fonts are loaded properly, and the faux styles are nowhere to be seen! The problem is that if your custom font doesn’t load for some reason, the browser is no longer applying bold or italic styles to the fallback font.

fallback font with no bold or italics

fig c: no bold or italic styles if custom font fails to load

So I think we can agree that this solution doesn’t work. It requires a lot of CSS to override built-in browser styles, and it breaks completely when the custom font doesn’t load. Luckily, there’s a better solution:

The Right Solution

Instead of defining separate font-family values for each font, You can use same font-family name for each font, and define the matching styles, like so:

@font-face {
	font-family: 'Ubuntu';
	src: url('Ubuntu-R-webfont.eot');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'Ubuntu';
	src: url('Ubuntu-I-webfont.eot');
	font-weight: normal;
	font-style: italic;
}
@font-face {
	font-family: 'Ubuntu';
	src: url('Ubuntu-B-webfont.eot');
	font-weight: bold;
	font-style: normal;
}
@font-face {
	font-family: 'Ubuntu';
	src: url('Ubuntu-BI-webfont.eot');
	font-weight: bold;
	font-style: italic;
}
.test {
	font-family: Ubuntu, arial, sans-serif;
}

Then all you need to do is apply that single font-family to your target, and any nested bold or italic styles will automatically use the correct font, and still apply bold and italic styles if your custom font fails to load.

correct fonts, with fallback styles

fig d: properly defined italic and bold fonts with fallback styles

You can see a live example of these problems and the final solution on the demo page.

Seriously, Microsoft?

Comparing font-face rendering between Mac and Win XP

fig e: comparison of @font-face on Macintosh and Windows XP

Also, I know it’s old news that type rendering on Macintosh is better than Windows, but seriously, when I see results like this (look at the lowercase ‘d’ – it’s a travesty!), I consider telling my clients it’s not worth it, because their beautiful custom fonts are going to look awful to over half the visitors to their website. I’ve heard Windows 7 has better rendering, but I don’t have a copy to test. All I can do at this point is trust that things will continue to improve, and enjoy how pretty things look on my Mac.


I love when front-end guys and designers comment on stuff like the lower case d. I mean, I see that it's different but I don't see how it's a travesty. Okay, actually travesty is the exact right definition but I feel like most people define travesty as something closer to anathema or heresy rather than just gross mockery.

Anyways, insightful and smart as usual. You're such a rockstar it hurts sometimes.


hello,
thank you for this post.
it is solving the exact problem i am having-- only not quite.
if you go to my linked site (rikedoepp.com)
you can see that the italic font loads first, then is changed to a non-italic font immediatley after.
do you know what may be causing this?

thanks!
b


Hm, and is there a way to force that faux italic? Font I am using doesn't have italic so I would love browser to make it that way. But when I define the font, the browser won't do that. When I use it locally from my PC (without defining by @font-face) it can make faux italic.


Just wondering: what if I want to define some text as bold using CSS and not using the strong tag? For example, if I want my navigation menu to be bold text. It makes more sense to define that in my CSS file rather than using strong tags. So in this case, how do I define it using a properly embedded web font, i.e. "The Right Solution" above?

Thanks!


Just FYI, IE 8 and below does NOT support font-style and font-weight under @font-face.

Just another reason why people should either use Chrome or Firefox, or at least IE 9...

Also, the type rendering being ugly doesn't happen in non-IE browsers as well, if I'm correct.


I have same problem with Alex Park.
This method not work for me in ie8 and below, her use only first @face-font in line.

Congratulations on the excellent article =)


Ya know, I'm usually picky about code but with the @font-face embedding I just grabbed the Font Squirrel stuff and threw it in with nary a problem. Until today. Then I Googled and found out a better way to handle the CSS. You helped fix my problem and avoid future issues. Thanks!


This problem (the double-bolding/italicing vs. the no fallback) has been bugging me for months, since we started using webfonts.fonts.com for some sites at my job. It was nice to find this blog post. Unfortunately, the developer is not able to change the font-family names to be the same when using this service, so I don't think there is a way to implement this solution. I will contact them with the suggestion. Thanks for the post!


Thanks for the strategy talk! Was facing these problems, but I wasn't aware that you could define font-style and font-weight in the @fontface declaration. Cheers!


Great Scott! Thanks for a great explanation to this issue. However, what about me who uses CSS reset for all my projects? I don't like to have differing browser styling playing around with the layout, however in this case it results in a matter of specificity. Am I missing something out or do I just have to cope with typography related browser styling?


Hi
How would that work for font with 14 typefaces ?
Correct me if I am wrong but your Right solution does not work on atleast IE7 and IE8. The wrong solution works perfect btw.

Best wishez


@Stojjan: 14 typefaces should be no problem. Here's an example using Open Sans on Font Squirrel, which comes in five weights (including italics for each, for 10 typefaces total). Note that I've assigned the "regular" typeface to font-weight: 400, and "bold" to font-weight: 700 -- you could also use font-weight: normal and font-weight: bold -- the spec say normal is 400 and bold is 700.

@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-Light-webfont.eot');
    src: url('OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-Light-webfont.woff') format('woff'),
         url('OpenSans-Light-webfont.ttf') format('truetype'),
         url('OpenSans-Light-webfont.svg#OpenSansLight') format('svg');
    font-weight: 200;
    font-style: normal;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-LightItalic-webfont.eot');
    src: url('OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-LightItalic-webfont.woff') format('woff'),
         url('OpenSans-LightItalic-webfont.ttf') format('truetype'),
         url('OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg');
    font-weight: 200;
    font-style: italic;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-Regular-webfont.eot');
    src: url('OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-Regular-webfont.woff') format('woff'),
         url('OpenSans-Regular-webfont.ttf') format('truetype'),
         url('OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
    font-weight: 400;
    font-style: normal;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-Italic-webfont.eot');
    src: url('OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-Italic-webfont.woff') format('woff'),
         url('OpenSans-Italic-webfont.ttf') format('truetype'),
         url('OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg');
    font-weight: 400;
    font-style: italic;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-Semibold-webfont.eot');
    src: url('OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-Semibold-webfont.woff') format('woff'),
         url('OpenSans-Semibold-webfont.ttf') format('truetype'),
         url('OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
    font-weight: 600;
    font-style: normal;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-SemiboldItalic-webfont.eot');
    src: url('OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-SemiboldItalic-webfont.woff') format('woff'),
         url('OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
         url('OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
    font-weight: 600;
    font-style: italic;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-Bold-webfont.eot');
    src: url('OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-Bold-webfont.woff') format('woff'),
         url('OpenSans-Bold-webfont.ttf') format('truetype'),
         url('OpenSans-Bold-webfont.svg#OpenSansBold') format('svg');
    font-weight: 700;
    font-style: normal;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-BoldItalic-webfont.eot');
    src: url('OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-BoldItalic-webfont.woff') format('woff'),
         url('OpenSans-BoldItalic-webfont.ttf') format('truetype'),
         url('OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg');
    font-weight: 700;
    font-style: italic;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-ExtraBold-webfont.eot');
    src: url('OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-ExtraBold-webfont.woff') format('woff'),
         url('OpenSans-ExtraBold-webfont.ttf') format('truetype'),
         url('OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold') format('svg');
    font-weight: 900;
    font-style: normal;
}
@font-face {
    font-family: 'OpenSans';
    src: url('OpenSans-ExtraBoldItalic-webfont.eot');
    src: url('OpenSans-ExtraBoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('OpenSans-ExtraBoldItalic-webfont.woff') format('woff'),
         url('OpenSans-ExtraBoldItalic-webfont.ttf') format('truetype'),
         url('OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic') format('svg');
    font-weight: 900;
    font-style: italic;
}

The examples in the blog post are abbreviated for clarity, but this is the full code, including loading all the different font files for each typeface: TTF for modern browsers, EOT for IE, WOFF for future-proofing, and SVG for iOS (though that's not needed anymore, since iOS now reads TTF).

You mentioned that the examples I provided don't work in IE -- I've never had that problem. In fact, I'm using this technique on all the sites I work on.

The key is simply to make sure that all the @font-face rules declare the same font-family value, with unique font-weight and font-style combinations.


I just checked how I did it few months ago. I choosed to use "The wrong solution" cause it seems more logical to me to have different name for each font.

@font-face {
    font-family: 'dinbold';
    src: url('fonts/ff_din_bold-webfont.eot');
    src: url('fonts/ff_din_bold-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/ff_din_bold-webfont.woff') format('woff'),
         url('fonts/ff_din_bold-webfont.ttf') format('truetype'),
         url('fonts/ff_din_bold-webfont.svg#dinbold') format('svg');
    font-weight: normal;
    font-style: normal;
}
 
@font-face {
    font-family: 'dinlight';
    src: url('fonts/ff_din_light-webfont.eot');
    src: url('fonts/ff_din_light-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/ff_din_light-webfont.woff') format('woff'),
         url('fonts/ff_din_light-webfont.ttf') format('truetype'),
         url('fonts/ff_din_light-webfont.svg#din_lightregular') format('svg');
    font-weight: normal;
    font-style: normal;
}
 
@font-face {
    font-family: 'dinregular';
    src: url('fonts/ff_din_regular-webfont.eot');
    src: url('fonts/ff_din_regular-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/ff_din_regular-webfont.woff') format('woff'),
         url('fonts/ff_din_regular-webfont.ttf') format('truetype'),
         url('fonts/ff_din_regular-webfont.svg#dinregular') format('svg');
    font-weight: normal;
    font-style: normal;
}
 
@font-face {
    font-family: 'dinmedium';
    src: url('fonts/ff_din_medium-webfont.eot');
    src: url('fonts/ff_din_medium-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/ff_din_medium-webfont.woff') format('woff'),
         url('fonts/ff_din_medium-webfont.ttf') format('truetype'),
         url('fonts/ff_din_medium-webfont.svg#dinregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

No offense.


I have Helvetica installed on my Windows 7 system and I use Firefox as my primary browser. This leads to some problems whenever a website specifies "helvetica, arial" in its css, because Helvetica is rendered especially poorly in Firefox at small sizes.

So, a common solution is to hack the userContent.css file in your Firefox profile folder and add such things as

@font-face { 
	font-family: 'HelveticaNeue';
	src: local('Arial');
}
@font-face {
	font-family: 'helvetica neue';
	src: local('Arial');
}
@font-face {
	font-family: 'helvetica';
	src: local('Arial');
}

which is wrong.

As explained in this post, you would get faux arial bold whenever some form of helvetica bold is required.

This post inspired me to hack my own userContent.css like this

@font-face {
	font-family: 'Helvetica Neue';
	src: local('Arial');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'Helvetica Neue';
	src: local('Arial italic');
	font-weight: normal;
	font-style: italic;
}
@font-face {
	font-family: 'Helvetica Neue';
	src: local('Arial bold');
	font-weight: bold;
	font-style: normal;
}
@font-face {
	font-family: 'Helvetica Neue';
	src: local('Arial italic bold');
	font-weight: bold;
	font-style: italic;
}
 
@font-face {
	font-family: 'HelveticaNeue';
	src: local('Arial');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'HelveticaNeue';
	src: local('Arial italic');
	font-weight: normal;
	font-style: italic;
}
@font-face {
	font-family: 'HelveticaNeue';
	src: local('Arial bold');
	font-weight: bold;
	font-style: normal;
}
@font-face {
	font-family: 'HelveticaNeue';
	src: local('Arial italic bold');
	font-weight: bold;
	font-style: italic;
}
 
@font-face {
	font-family: 'Helvetica';
	src: local('Arial');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'Helvetica';
	src: local('Arial italic');
	font-weight: normal;
	font-style: italic;
}
@font-face {
	font-family: 'Helvetica';
	src: local('Arial bold');
	font-weight: bold;
	font-style: normal;
}
@font-face {
	font-family: 'Helvetica';
	src: local('Arial italic bold');
	font-weight: bold;
	font-style: italic;
}

I specified rules for Helvetica, Helvetica Neue and HelveticaNeue just to be sure: I noticed all three forms are found in css sheets around the web. There might be more, so my script is probably not exhaustive. Just add the relevant cases whenever applicable.

This seems to work, so I thought I'd share.

Interestingly enough, IE doesn't seem to render Helvetica quite as poorly as Firefox, but I'm not going to switch browsers anyway.


Hi, thanks Scott. And all the people who posted the comments. I was strugling with @font-face. Especially with bold and italic. I tried the fontsquirl package. Didn't work right. But the solucion of valerio on June 17, 2012 works perfect. My client is very happy now. ;)


The reason why Fontsquirrel and the like have been using the "wrong solution" is a bug on IE 9 and 10 in compatibility mode. The "right solution" works perfectly on IE 7 and 8 and I had been using it until the release of IE 9 but they don't render at all on IE 9 and 10 in compatibility view unless you use the "wrong solution". I know most people shouldn't be using compatibility view anyway but it's pretty easy to activate by accident and some people are stuck in that mode without even knowing it. If you want your fonts to render correctly for those people, you have to use the "wrong solution", even though it can be a real pain sometimes.


Thanks Scott, exactly what I was looking for. Luckily I found your article as not many people adress this problem.


This is an all in one great solution, and it works like a charm. Thanks for sharing.

Add new comment

Restricted HTML

  • Web page addresses and email addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <h4> <h5> <h6>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>&lt;code&gt;</code>, <code>&lt;blockcode&gt;</code>, <code>&lt;apache&gt;</code>, <code>&lt;c&gt;</code>, <code>&lt;cpp&gt;</code>, <code>&lt;css&gt;</code>, <code>&lt;drupal5&gt;</code>, <code>&lt;drupal6&gt;</code>, <code>&lt;html&gt;</code>, <code>&lt;java&gt;</code>, <code>&lt;javascript&gt;</code>, <code>&lt;mysql&gt;</code>, <code>&lt;php&gt;</code>, <code>&lt;python&gt;</code>, <code>&lt;ruby&gt;</code>, <code>&lt;sql&gt;</code>, <code>&lt;xml&gt;</code>. The supported tag styles are: <code>&lt;foo&gt;</code>, <code>[foo]</code>.

About the Author