Using CSS3 @font-face to “fake” multiple font weights

CSS2 specifies additional font weights, beyond Normal and Bold. In particularly there are 9 font weights in total – 100, 200, 300, 400 (normal), 500, 600 (bold), 700, 800 and 900. Unfortunately browsers still somewhat lack support for this feature, but more importantly fonts lack support for this. Many fonts however, still come with only normal and bold weights. Moreover, based on a few tests, even professional fonts that come with multiple weights (such as thin, light, regular, bold, heavy, etc.) don’t actually support these weights in the same way as the CSS2 specification dictates, in other words they can’t be used out of the box like that.

For example, I have the Arno Pro font (a nice serif font from Adobe). It comes in 4 weights – regular, bold, light and semibold. Each is encapsulated in its own file with a distinct name, e.g. ArnoPro-Bold, ArnoPro-Smdb, ArnoPro-Light, etc. I don’t know much about how fonts work but based on a bit of reading I’ve done, for a font like that I should be able to declare a style that uses “ArnoPro” font-family and based on the weight I assign to a particular element it would use a different version. For example, ArnoPro-Light for 200, ArnoPro-Regular for 400 or normal, and so on. However, based on a few tests I’ve done that doesn’t seem to be the case. In fact “ArnoPro” font isn’t recognized at all, only if I specify explicitly “ArnoPro-Smbd” does it recognize the font. And of course when it’s done like that all but the regular version are stuck with one weight, i.e. font-family:ArnoPro-Smbd; font-weight:normal looks exactly the same as font-family:ArnoPro-Smbd; font-weight:bold.

In short, the situation is less than ideal. However, there may be a at least a partial fix.

Using @font-face, which was introduced in CSS3, you can simulate the extra font-weights by assigning the specific fonts to each weight. This is a kind of a hack, and one that will not work in all browsers. In fact, I only managed to get it to work in FF3.5. I think IE only supports this for their proprietary font format, which I didn’t used, and for some reason it didn’t work in Chrome 2 either (which I thought supported @font-face), but I didn’t investigate this further, at least not for now.

The way @font-face works is that whatever font attributes you specify for a @font-face rule, they don’t determine how the font looks but rather when it’s gonna get used. For example if you have the following two rules

@font-face {
	font-family: newfont;
	src: local(Arial);
	font-weight: 200;
}
@font-face {
	font-family: newfont;
	src: local(Calibri);
	font-weight: 300;
}

Then if you use the “newfont” font-family with weight 200 it’s going to use Arial, but if you use it with weight 300 it’s going to use Calibri. So we can take advantage of that, and since it uses @font-face we don’t even have to worry if the user’s computer has fonts or not.

For this test I used a Kaffeesatz, a nice looking opentype sans-serif font from Yanone Schriftgestaltung. The font comes with four weights, Thin, Light, Regular and Bold. I used the following styles to create 200 and 300 weights, in addition to normal and bold.

@font-face {
	font-family: Kaffeesatz;
	src: url(YanoneKaffeesatz-Thin.otf);
	font-weight: 200;
}
@font-face {
	font-family: Kaffeesatz;
	src: url(YanoneKaffeesatz-Light.otf);
	font-weight: 300;
}
@font-face {
	font-family: Kaffeesatz;
	src: url(YanoneKaffeesatz-Regular.otf);
	font-weight: normal;
}
@font-face {
	font-family: Kaffeesatz;
	src: url(YanoneKaffeesatz-Bold.otf);
	font-weight: bold;
}
h3, h4, h5, h6 {
	font-size:2em;
	margin:0;
	padding:0;
	font-family:Kaffeesatz;
	font-weight:normal;
}
h6 { font-weight:200; }
h5 { font-weight:300; }
h4 { font-weight:normal; }
h3 { font-weight:bold; }

As you can see I defined one font family – Kaffeesatz, and for each weight imported a different font file. After the @font-face rules are defined I can use the 200 and 300 font weights just as I would normal and bold, and the HTML below

<h6>The quick brown fox Jumps over the lazy Dog. 1234567890</h6>
<br>
<h5>The quick brown fox Jumps over the lazy Dog. 1234567890</h5>
<br>
<h4>The quick brown fox Jumps over the lazy Dog. 1234567890</h4>
<br>
<h3>The quick brown fox Jumps over the lazy Dog. 1234567890</h3>

produces the following text

fontweights

Pretty neat if I may say so myself.

This is definitely more hassle than it should be, and of course requires you to find an open font that you can use with all the weights you need. However, as more browsers begin supporting @font-face, and as font support in browsers grows in general, typography will become more important on the web and hopefully many more fonts will start supporting multiple weights.

(9) Comments

  1. franky
    July 22, 2009

    That’s a nice trick there. Though as you said, since it only works in FF3.5 its use is pretty limited.

  2. Greg
    July 23, 2009

    I want to start doing tutorials on CSS3 – I want to be ahead of the curve like you.

  3. stoimen
    July 23, 2009

    The problem is that most of the things posted in the last few months related to ecmascript5, html5 and CSS3 are only applicable to certain browsers, but we’d like to see them working on every one.

    In fact that doesn’t make the CSS3 groovy features bad, but sadly we cannot use them because of that compatibility reason.

  4. Cobey P
    July 23, 2009

    Couldn’t you do this is a similar fashion where you define the four weights as a different font-family for each, and instead of setting the font-weight, you instead just supply the singular font-family?

    h3, h4, h5, h6 {
    font-size:2em;
    margin:0;
    padding:0;
    font-family:Kaffeesatz;
    }
    h6 { font-family:Kaffeesatz1; }
    h5 { font-family:Kaffeesatz2; }
    h4 { font-family:Kaffeesatz3; }
    h3 { font-family:Kaffeesatz4; }

    obvious, as you said, more hassle, and I haven’t tested it, but I would think that this would work in all browsers that handle @font-face.

    • ilia
      July 23, 2009

      I’m not sure why it only works in FF3.5, that’s something I might look into. Theoretically, any browser with @font-face support should be able to do this. (The other browser I tested this in is Chrome, it’s possible that Safari 4 has a better @font-face support.)
      In any case though, while certainly you could just give a different font-family name to each weight it kinda defeats the purpose of using weights as they are intended to :)

      P.S. Not sure why this comment always appears last, this was a reply to Cobey P’s original comment. Must have something to do with replying from within the WP Dashboard. Oh well, live and learn.

  5. Cobey P
    July 23, 2009

    oh, I agree completely about it “defeating the purpose”.

    Your piece does clear up some issues I had with understanding how font-weight works within @font-face. It appears that it acts like a filter, which is good to know.

    I assume that font-style:italic would be the same sort of thing, yes?

    Thanks for the post

  6. ilia
    July 23, 2009

    @Cobey P: “I assume that font-style:italic would be the same sort of thing, yes?”

    I believe so, but I haven’t done any testing.

  7. Jon Rohan
    July 23, 2009

    This works in safari 4, and even IE has support for open type fonts and @font-face

  8. stk
    August 28, 2009

    ilia – It is theoretically possible to utilize this technique cross-browser, though it may require specifying font-family, rather than font-weight.

    Here’s how: http://randsco.com/index.php/2009/07/04/cross_browser_font_embedding

Trackbacks

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>