Avatar of Geoff Graham
Geoff Graham on (Updated on )

The unicode-range property in CSS is used by the @font-face to define the characters that are supported by the font face.

@font-face {
  font-family: 'MyWebFont'; /* Define the custom font name */
  src:  url('myfont.woff2') format('woff2'),
        url('myfont.woff') format('woff'); /* Define where the font can be downloaded */
  unicode-range: U+00-FF; /* Define the available characters */

In other words, @font-face will refer to the property and determine whether or not it should download and use the font based on whether the characters or range of characters match those in the HTML document.

Font Face: Hey HTML, do any of the following characters match what is on the page?
HTML: Yep, a bunch of them do.
Font-Face: Great, here is a font file you should download to display those characters.

The important semantic distinction we should call out here is that unicode-range determines what characters a font can be used for, rather than what characters a font is available to use. In other words, if we declare a unicode-range on @font-face and the characters that have loaded in an HTML document match that range, then the font will download and be put to use.

You can imagine the performance benefits that open up with this property. For example, we can load a custom font only if it accommodates specific characters rather than always loading the font in all situations.

There’s even a way to combine two @font-face sets on the on the same font-face property declaration, thanks to a handy trick shared by Jake Archibald. The idea is that one @font-face set overrides the other based on the matched unicode-range, optimizing performance, or simply enhancing the typography on a page.


Any unicode character code or range is an acceptable unicode-range value. You will notice that unicode points are preceded by a U+ followed by up to six characters that make up the character code. Points or ranges that do not follow this format are considered invalid and will cause the property to be ignored.

  • Single Character (e.g. U+26)
  • Character Range (e.g. U+0025-00FF)
  • Wildcard Range (e.g. U+4??)

The Wildcard Range is the tricky one of the bunch. Each ? represents a wildcard where any value will match. You’d think that means you can wildcard the whole thing with something like this:

@font-face {
  font-family: 'MyWebFont';
  src:  url('myfont.woff2') format('woff2'),
        url('myfont.woff') format('woff');
  unicode-range: U+??????; /* This does not work! */

However, this will not work. The reason is that leading with ? implies a character code that leads with 0, meaning that up to five question mark characters can be used despite unicodes accepting up to six total characters.

@font-face {
  font-family: 'MyWebFont';
  src:  url('myfont.woff2') format('woff2'),
        url('myfont.woff') format('woff');
  unicode-range: U+?????; /* This works and is equivalent to U+0????? */

There are a ton of unicode options out there. Basic Latin (0020—007F) is probably the most common range for English sites, but unicode-table.com provides a comprehensive listing of all available ranges with codes for specific characters.

Browser Support

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.



Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari

Further Reading