CSS Font Rendering Controls Module Level 1

Unofficial Proposal Draft,

This version:
https://tabatkins.github.io/specs/css-font-display/
Issue Tracking:
GitHub
Inline In Spec
Editors:
Tab Atkins (Google)
Kenji Baheux (Google)

Abstract

This spec introduces a new @font-face descriptor and a corresponding property for controlling how a downloadable font renders before it is fully loaded. It’s intended that this spec be merged into the Fonts spec, likely Fonts Level 4.

Table of Contents

1. Introduction

When using downloadable webfonts via @font-face, the user agent needs to know what to do while the font is actively loading. Most web browsers have adopted some form of timeout:

Browser Timeout Fallback Swap
Chrome 35+ 3 seconds yes yes
Opera 3 seconds yes yes
Firefox 3 seconds yes yes
Internet Explorer 0 seconds yes yes
Safari no timeout n/a n/a

While these default behaviors are reasonable, they’re unfortunately inconsistent across browsers. Worse, no single approach is sufficient to cover the range of use-cases required by modern user-experience– and performance–conscious applications.

The Font Loading API [CSS-FONT-LOADING-3] allows a developer to override some of the above behaviors, but that requires scripting, a non-trivial amount of effort, and ultimately doesn’t provide sufficient hooks to cover all reasonable cases. Additionally, the developer needs to either inline the loading script into their page or load an external library, introducing additional network latency before the fonts can be loaded and delaying text rendering.

Design/performance-conscious web developers have a good sense for the relative importance of a given web font for the intended user experience. This specification provides them the ability to control font timeout and rendering behavior. Specifically, it lets developers:

2. The Font Display Timeline

At the moment the user agent first attempts to use a given downloaded font face on a page, the font face’s font download timer is started. This timer advances through three periods of time associated with the font face-- the block period, the swap period, and the failure period-- which dictate the rendering behavior of any elements using the font face:

To render with a fallback font face for a given element, the user agent must find the first font face specified in the element’s font-family list which is already loaded, and use that for rendering text. Doing this must not trigger loads of any of the fallback fonts.

To render with an invisible fallback font face for a given element, find a font face as per "render with a fallback font face". Create an anonymous font face with the same metrics as the selected font face but with all glyphs "invisible" (containing no "ink"), and use that for rendering text. Doing this must not trigger loads of any of the fallback fonts.

fallback and optional can result in some faces in a family being used while others are required to fallback, giving a "ransom note" look. Perhaps require that all fonts in a family have the same behavior (all swapped in, or all fallback)?

3. Controlling Font Display Per Font-Face: the font-display descriptor

The font-display descriptor for @font-face determines how a font face is displayed, based on whether and when it is downloaded and ready to use.

Name: font-display
For: @font-face
Value: auto | block | swap | fallback | optional
Initial: auto

Note: For all of these values, user agents may use slightly different durations, or more sophisticated behaviors that can’t be directly expressed in the font-display syntax, in order to provide more useful behavior for their users. They may also provide the ability for users to override author-chosen behavior with something more desirable; for example, forcing all fonts to have a 0s block period.

auto
The font display strategy is user-agent-defined.

Note: Many browsers have a default strategy similar to that specified by block.

block
Gives the font face a short block period (3s is recommended in most cases) and an infinite swap period.

Note: In other words, the browser draws "invisible" text at first if it’s not loaded, but swaps the font face in as soon as it loads.

This value must only be used when rendering text in a particular font is required for the page to be usable. It must only be used for small pieces of text.

For example, badly designed "icon fonts" might associate a "⎙" (print) icon with an unrelated character like "C", so if the text is displayed with a fallback font instead there will be confusing letters scattered around the page rather than the desired icon. In this case, temporary blank spots are better than using a fallback font.

(However, the fallback font is used eventually, as having confusing letters scattered around the page is better than having links and such never show up at all.)

swap
Gives the font face a 0s block period and an infinite swap period.

Note: In other words, the browser draws the text immediately with a fallback if the font face isn’t loaded, but swaps the font face in as soon as it loads.

This value should only be used when rendering text in a particular font is very important for the page, but rendering in any font will still get a correct message across. It should only be used for small pieces of text.

For example, if a website has a custom font for rendering their logo, rendering that logo correctly is fairly important for branding purposes, but displaying the logo in any font will at least get the point across without confusion.
fallback
Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a short swap period (3s is recommended in most cases).

Note: In other words, the font face is rendered with a fallback at first if it’s not loaded, but it’s swapped in as soon as it loads. However, if too much time passes, the fallback will be used for the rest of the page’s lifetime instead.

This value should be used for body text, or any other text where the use of the chosen font is useful and desired, but it’s acceptable for the user to see the text in a fallback font. This value is appropriate to use for large pieces of text.

For example, in large pieces of body text, it’s most important just to get the text rendered quickly, so the user can begin to read as quickly as possible. Further, once the user has started reading, they shouldn’t be disturbed by the text suddenly "shifting" as a new font is swapped in, as that’s distracting and annoying to re-find where one was in the text.
optional
Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a 0s swap period.

If the font is not retrieved before the two durations expire, the user agent may choose to abort the font download, or download it with a very low priority. If the user agent believes it would be useful for the user, it may avoid even starting the font download, and proceed immediately to using a fallback font.

Note: In other words, the font is used if it’s already downloaded and available, but otherwise a fallback is used for the rest of the page’s lifetime instead. The font might download in the background and be available to future page loads, but if the user-agent detects that the user has very limited bandwidth, it might choose to simply never download and use the font.

This value should be used for body text, or any other text where the chosen font is purely a decorative "nice-to-have". It should be used anytime it is more important that the web page render quickly on first visit, than it is that the user wait a longer time to see everything perfect immediately.

For example, body text is perfectly readable in one of the browser default fonts, though a downloadable font face may be more attractive and mesh with the site’s aesthetics better. First time visitors to a site generally care far more about the site being quickly usable than they do about the finer points of its display, and optional provides a good behavior for them. If they return later, the desired font faces might have finished downloading, giving them the "intended" experience without slowing down either their first or subsequent visits.

Users on very slow connections might not ever receive the "intended" experience, but optional ensures they can actually use the site, rather than quitting and going elsewhere because the site takes too long to load.

These names aren’t great. It would probably be better to use "intent" names that immediately capture the intended usage of each. Some suggestions:

4. Acknowledgements

Special thanks to Ilya Grigorik and David Kuettel for their help in developing this specification.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-FONTS-3]
John Daggett. CSS Fonts Module Level 3. 3 October 2013. CR. URL: http://www.w3.org/TR/css-fonts-3/
[CSS-VALUES]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 11 June 2015. CR. URL: http://www.w3.org/TR/css-values/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119

Informative References

[CSS-FONT-LOADING-3]
Tab Atkins Jr.. CSS Font Loading Module Level 3. 22 May 2014. LCWD. URL: http://www.w3.org/TR/css-font-loading-3/

Property Index

No properties defined.

@font-face Descriptors

Name Value Initial
font-display auto | block | swap | fallback | optional auto

Issues Index

fallback and optional can result in some faces in a family being used while others are required to fallback, giving a "ransom note" look. Perhaps require that all fonts in a family have the same behavior (all swapped in, or all fallback)?
These names aren’t great. It would probably be better to use "intent" names that immediately capture the intended usage of each. Some suggestions: