Creating Custom Font Stacks with Unicode-Range

48 Comments

Comments are ordered by helpfulness, as indicated by you. Help us pick out the gems and discourage asshattery by voting on notable comments.

Got something to add? You can leave a comment below.

  1. Drew McLellan

    Is that the actual behaviour, or is that just the expected behaviour?

    It’s both actual and expected.

    Would an alternative fallback be to strip down the font (using, say, FontForge) so that it only includes the characters to be substituted?

    Yes, that would be ideal where possible.

  2. Jake Archibald

    Webkit is super smart with unicode-range. It’ll only download the ampersand font if you use an ampersand. Because it gives the browser advance knowledge of the usable chars in the font, webkit will download fonts in parallel rather than series.

  3. Jon Tan

    Brilliant piece, Drew!

    Regarding unicode range and subsets: At Fontdeck we have tiny fonts we call ‘expert subsets’ containing only OpenType features like swashes for some faces like Pimlico and Trilogy. Firefox 4 supports CSS 3 OpenType features. For the rest, specific characters can be displayed using OpenType alternates, swashes, or anything else, using regular HTML hooks. However, this is better way if the fine folks at Mozilla can implement it.

    Rich Rutter has described subsets as a modular approach. I agree, and refer to them already as modular font stacks. Including special features in small files that can progressively enhance the type, perhaps selected with this method, makes a lot of sense for those of us concerned with performance and extensibility.

  4. Natalie Downe

    Hi Drew, fab article to kick off this year’s 24ways! I didn’t know you could do that with unicode range!

    I know that ampersands were just the example not your necessary intention, however I though that was a really good use of it and have implemented better ampersands on Lanyrd now:

    An Example, The Art & Science of Javascript

    We are using Eigerdals (through Fontdeck) for the heading typeface, which I adore, but I have never been keen on the ampersand, it looked a little too much like a ligature for Et. So using the technique you demonstrated I have switched to Hoefler Text just for the ampersands.

    However, I see one big flaw with this: how are you to style the ampersand itself? For example, you may want the ampersand to be italic, it may have a different x-height so needs a different font-size and so on and so forth.

    I discovered that the ampersands I wanted to use were all in the italic font and naturally I wanted my titles not to be. So I used the ‘PostScript Name’ of the individual font style I wanted to use rather than the family, and this worked.

    Our stack for example is:

    src: local(‘HoeflerText-BlackItalic’), local(‘AGaramondPro-BoldItalic’), local(‘MinionPro-BoldIt’), local(‘AdobeHebrew-BoldItalic’);

    I deliberately only have fallbacks that looked as I wanted them, because if it cant find one of those it falls back to Eigerdals. For Firefox I gave the @font-face rule the same fallback stack as I had for the title text originally.

  5. Ryan Seddon

    Instead of using that hideous conversion website, here’s a little javascript snippet that will convert a character to its unicode hex equivalent

    “✌”.charCodeAt(0).toString(16); // “270c”

  6. barryvan

    Have you checked that this issue is logged as a bug in bugzilla? Given that this is a quite a niche use (at least at present), it’s not unlikely that the Firefox developers aren’t even aware of this issue.

    Also, you say that “the font shouldn’t be downloaded if none of the characters within the Unicode range are present in a given page.” Is that the actual behaviour, or is that just the expected behaviour?

    Would an alternative fallback be to strip down the font (using, say, FontForge) so that it only includes the characters to be substituted? I understand that some fonts’ licensing and distribution methods preclude this, but for other fonts, it could potentially mean less fallback CSS and smaller font downloads.

  7. Matt Hobbs

    Great article, I had no idea it that was possible. I just hope it doesn’t get taken to the extreme, a different font per character… urghh! There’s always a client somewhere who will want it.

  8. MarvelousGenki

    Awww :3 There we are again. Great to have you here on the worlds most brilliant advent calendar.

    Very interesting article, as ever.
    Used @fontface a lot and never knew unicode-range existed. Thank you!

    How do I declare multiple characters?
    unicode-range: character, character, character; ?
    A new fontface rule for every special character seems a bit dull, especially, when they’re nested in the same font ö.ö

  9. Dan Griffey

    It would be nice to hear which has the widest compatibility and best server / client side performance for those of us running big sites. <span> vs UTF. Thanks.

  10. Luke Jones

    This is a lovely technique and in some ways is preferable to using span.amp, for example. However, I see one big flaw with this: how are you to style the ampersand itself?

    For example, you may want the ampersand to be italic, it may have a different x-height so needs a different font-size and so on and so forth.

    That being said, it’s extremely exciting.

  11. Jason Zipperer

    Couldn’t you use a unicode range that excluded the ampersand with Arial, and list that before your ampersand font. That way the natural fallback would be Arial for everything?

  12. Aaron

    Why not just use javascript to find all “&” and replace them with <span class=“ampersand”>&</span>?

    At least this way, your CSS and HTML will be clean.

    http://patrickhaney.com/thinktank/2008/08/19/automatic-awesompersands

  13. nemo20000

    Couldn’t you do the reverse – specify an everything-but-ampersand range for the body fonts and an underlying fancy one for the remaining ampersand?

  14. Jon Spooner

    I’ve seen folks using the icon fonts like Dingbats etc for stylish bullets and so forth and I gather you could use this Unicode trick to allow you to use various dingbats from various font faces.

    One question about the implementation of the code. Does just loading a certain range of unicode characters lower the download from the entire font library? say you ref Mrs Eaves as a font-face but only want the ‘& does using this unicode statement limit the download to just the & character or is the whole Mrs. Eaves font downloaded and only the one character is rendered?

    I have seen in the case of Google Fonts where you can just link to a smaller font file if you are going use certain characters and not the whole alphabet.

  15. Michael Heap

    Would an alternative fallback be to strip down the font (using, say, FontForge) so that it only includes the characters to be substituted?

    Be careful when stripping down fonts. A lot of them only give you a license to use them in their entirety. If you start editing the font, you start breaking their T&C’s.

  16. John Fish

    Very interesting article, I might use this. Just to be a nitpicker though, in the first CSS example you gave, the file extension was .ttf, however you gave it a format of opentype (rather than truetype). However, great thoughts, and really looking forward to the rest of the 24 ways this year :)

  17. Robert O'Rourke

    Excellent article Drew, a great start to the series.

    FWIW:

    With regards to the notion some people are passing round that Firefox is the new IE. This is utterly bonkers. None of the modern browsers being released now are “the new IE”. Not even IE.

    At the rate FF releases are going it won’t be too long before unicode-range support lands. Not to mention for the time being font rendering is much better in FF than any other browsers (at least on windows) in terms of legibility and kerning which I think are more important than subsetting.

    Compared to FF, IE9 has no text-shadow, flexbox, gradients, transitions, webworkers… the list goes on, but that doesn’t mean it’s a bad browser.

  18. Drew McLellan

    Couldn’t you use a unicode range that excluded the ampersand with Arial, and list that before your ampersand font.

    In theory, you could. That would mean scoping a range above and below the characters you wanted to exclude. Browsers don’t currently support multiple ranges properly, so each range would need its own @font-face rule to do so.

    It works, but you end up with much more complex and hard to maintain rules.

    Why not just use javascript to find all “&” and replace them with <span class=“ampersand”>&</span>?

    Because ampersands are the example, not the end goal.

  19. Jeremy Caudle

    24ways starts off another year with a great post containing info that I can immediately put into practice.

    Thanks Drew, you’ve just given me a solution to a problem that’s been buggin me for the entire year!

  20. John Daggett

    I’m a little confused by your write-up here, the behavior you describe is different from your example. In your example the @font-face rule containing ‘local(Arial)’ follows the one containing ‘local(Baskerville)’. This renders the same in Firefox 8, Safari 5, Chrome 17 and IE9, it always uses Arial. The behavior you describe (Firefox showing Baskerville) actually occurs if you use the reverse order than the one shown in your example. Here’s a testpage showing the variations.

    The unicode-range descriptor is really intended to help better control load behavior for subsetted fonts designed to support a wide variety of scripts and languages. Especially for CJK fonts, these can be rather large. An author can include a set of subsetted fonts to support Japanese and via unicode-range assure that those fonts are only downloaded when Japanese characters are actually used on the page.

    With multiple @font-face rules for the same style settings, the CSS3 Fonts spec defines how these rules are referenced:

    If the unicode ranges overlap for a set of @font-face rules with the same family and style descriptor values, the rules are ordered in the reverse order they were defined; the last rule defined is the first to be checked for a given character.

    So the last @font-face rule defined is the first one matched. The reason this is specified this way is so that an @font-face rule defined later can override a specific range. If the compounding worked the other way, a given @font-face rule that didn’t specify a unicode-range descriptor couldn’t be overriden by later rules.

    This isn’t a case of Firefox not wanting to implement this feature, we’ve just been focused on better support for the rich typographic controls that are also part of CSS3 Fonts. Just a matter of priorities, we have every intention of implementing all features described in the spec.

    As for “opentype” vs. “truetype” format hints, the spec defines them to be synonymous. That’s due to the fact that the terms are used ambiguously and OpenType is a superset of TrueType.

    John Daggett
    Mozilla Japan
    CSS3 Fonts editor

  21. moni

    Nice, but you end up mixing and matching fonts inline. Of course that’s still better than a height:1em PNG. But what I’d really like to see is a true fallback for missing glyphs.

    Say I want to use the emoji characters and provide an emoji webfont for that range, but once the general font has native emoji glyphs, use those because they were designed to fit in with other text in that font.

    Now the only way to achieve that is to measure the rendered characters in Javascript and guess if they are present in the font or just a placeholder. Or use webfonts for everything (because I know the range of the fonts I provide), but that’s a big overhead.

  22. John Daggett

    @marc tamlyn

    On the subject of browser support – unicode-range works fine on iOS with but local doesn’t seem to work.

    Testing on iOS5, src local seems to work just fine. Here’s an example test page.

    The one caveat is that you need to use Postscript names, not fullnames (i.e. “Futura-MediumItalic” instead of “Futura Medium Italic”). If you’re using an OSX machine, open Fontbook, select a specific font, then select Preview > Show Font Info. Both the Postscript name and fullname are shown.

  23. Fraser Pearce

    Does putting the unicode-range first help?

    i.e.:

    @font-face {
    unicode-range: U+26;
    font-family: ‘Ampersand’;
    src: local(‘Baskerville’), local(‘Palatino’), local(‘Book Antiqua’);
    }

    Wouldn’t that then (in Firefox’s case) abort the @font-face rule parsing and thus no override the default font-face font the ampersand?

    (Sorry I don’t have time to check this idea right now)

  24. Andrew Yates

    Great post, I’ve used the <span> method for ampersands before when using font-face. Will definitely give this method a go.

    It does also raise the question, when is Firefox planning to support this? Does seem to be trailing behind somewhat lately with some people calling it the “new” IE.

  25. Kumo

    Brilliant!
    I had no idea that something like this existed! Could be really useful for symbols.

    With all the work that has been done on Internet Explorer lately, I’m a bit afraid that Firefox could become the new IE…
    :-/

  26. Kurt

    Very interesting post to start with this year.
    It is always regretful when a browser as popular as firefox doesn’t support it.
    In the past IE had the most problems, but recently it becomes more and more firefox.

  27. Andy Mabbutt

    I’ve been waiting all year for these features and first has not disappointed – thanks for this and in anticipation of those to follow!

    …and let’s not be too hard on FF; its achievements and driving influence on web design over the past few years have been prodigious.

  28. Reece Cropley

    Great article! I’ve only just discovered 24ways this year so looks like I’ve got some reading to do!

    I’ve never played around with Unicode but it looks a great way to spruce up your websites font.

  29. Marco

    A bit over the top for me. I don’t know why I should be using this.

    Typically I have a problem with fonts that they don’t support Spanish characters (ntilde, iacute, aacute, etc)

    Are you saying I should use this (a range) to include a font that might look similar to the one that doesn’t support it to have some coverage?

  30. Marc Tamlyn

    Thanks, this is exactly what we needed!

    On the subject of browser support – unicode-range works fine on iOS with but local doesn’t seem to work. Ended up just serving Symbol.ttf..

  31. Sebastian Green

    Great Article.

    I’m going to try it out in a HTML e-mail I do for a client on a monthly basis. It contains lots of &‘s.

    Place your bets for support in e-mail clients? Will keep you posted

Impress us

Be friendly / use Textile