onfontready

1.1.0 • Public • Published

onfontready 1.1.0

Font load and parse detection with minimal size and maximum compatibility.

Features

Install

Installation via NPM:

npm install --save onfontready

Installation via yarn:

yarn add onfontready

Pre-built distribution versions from the dist directory:

Basic Usage

Here is a very simple example usage that prevents FOIT, but will timeout the font loading attempt after 5 seconds. For more advanced usage, read Recipes and Usage Patterns.

  1. Import the desired font.

    • Describe a @font-face in CSS. (Using Font-Face at CSS-Tricks).

      @font-face {
          font-family: 'MyWebFont';
          src: url('myTheme/fonts/webfont.woff2') format('woff2'),
               url('myTheme/fonts/webfont.woff') format('woff');
      }
    • Or import the font using a web font service, such as Google Fonts.

      <link href="https://fonts.googleapis.com/css?family=Comfortaa" rel="stylesheet">
  2. Include onfontready.

    • Inline onfontready at the bottom of the HTML (recommended).

      <html>
          ...
          <script>
              // From onfontready.min.js
              window.onfontready=...;
          </script> 
      </html>
    • Or use script src to import onfontready at the bottom of the HTML.

      <html>
          ...
          <script src="dist/onfontready.min.js"></script> 
      </html>
    • Or include onfontready into Javascript codebase via CommonJS.

      var onfontready = require('onfontready');
  3. Call onfontready with appropriate options. This pattern attempts to load the font, but will timeout after 5 seconds. Read Recipes and Usage Patterns for more options and usage patterns.

    onfontready('MyWebFont', function() {
        document.documentElement.className += " fontLoaded";
    }, {
        timeoutAfter: 5000, // 5 seconds in milliseconds
        onTimeout: function() {
            document.documentElement.className += " fontNotLoaded";
        }
    });
  4. Define actions to take upon successful load (onReady is called) and/or load failure (options.onTimeout is called). In this pattern, fancyFontElement initially uses a sans-serif font. If the font loads successfully, the element will use the MyWebFont font. If the font fails to load, the element will use the monospace font and have grey text.

    .fancyFontElement {
        font-family: sans-serif;
    }
     
    .fontNotLoaded .fancyFontElement {
        font-family: monospace;
        color: #ddd;
    }
     
    .fontLoaded .fancyFontElement {
        font-family: 'MyWebFont'sans-serif;
    }

There are many other patterns possible. For example:

  • localStorage APIs can be used to optimize for second load.
  • Emulate font loading behavior of other browsers.
  • FOUT flickering can be prevented on first load.
  • Generic font family support can be detected.
  • Local installs of fonts can be detected.
  • Multiple fonts can be loaded or timed out as a unit.

Read Recipes and Usage Patterns for more.

API

By default, the onfontready function is attached to the window object. Using CommonJS, the function becomes available via the require() syntax. The function has two required arguments and one optional argument.

onfontready(fontName, onReady, [options={}])
  • fontName - (string) Name used in @font-face declaration, font name on the local client machine, or generic font family name.
  • onReady - (function callback) Called upon successful detection of the font's load and parse by the browser. No parameters.
  • options - (Object) Optional object for settings.
    • options.timeoutAfter - (number) Milliseconds waited before calling options.onTimeout callback. onfontready will wait indefinitely if options.timeoutAfter is unset or 0. Negative numbers are allowed and act as a "fast" timeout.
    • options.onTimeout - (function callback) Called after options.timeoutAfter milliseconds have elapsed without an onReady call.
    • options.generic - (boolean) Causes onfontready to detect generic font families like fantasy, cursive, san-serif, or BlinkMacSystemFont if set to true.
    • options.sampleText - (string) Text used for font width testing. This option should only be used for fonts that have no space character. There is only one known font without a space character.

Foundational Structure

onfontready only detects when fonts are loaded and parsed by a browser. It is intended to do only one thing, and serve as the foundation for more sophisticated tools.

Compression

onfontready has been code-golfed for gzip output size, not minified size. It is probably the smallest font detection library possible without setTimeout polling. To achieve this, onfontready contains some 'bad-practice' code structures and lots of seemingly unnecessary repetition. Code should always be gzipped, so the gzip size is ultimately more important than the minified size.

As this table demonstrates, onfontready is significantly smaller than comparable font detection libraries. All values are in bytes.

Compression onfontready onfontready legacy FontFaceObserver ◦
Minified * 901 1393 3981
gzip † 371 444 1479
zopfli ‡ 368 434 1463
brotli ¶ 277 327 1209

* - UglifyJS was used for minification.
† - gzip level 6, the default compression level.
‡ - Zopfli, an exhaustive search compression. It typically produces the smallest possible gzip-compatible output.
¶ - Brotli, a new higher-performing compression available to some modern browsers over HTTPS connections.
◦ - FontFaceObserver Standalone version 2.0.5 included for comparison. FontFaceObserver was already minified using the Google Closure compiler. For the table above, the minified code was run through UglifyJS to further compress it. Without UglifyJS, the compressed sizes would be larger for FontFaceObserver.

To learn more, read about the Compression Techniques used and read through the fully-commented source code.

Motivation

I was attempting to build a website with a size budget of less than 14KB gzipped for all HTML, CSS, JS, SVGs, and some inline images. I encountered a strange issue with inline SVGs (described below), which prompted me to research font loading in detail. The library I had been using, FontFaceObserver, while small, still accounts for over 1KB when gzipped, which was a huge dent in my size budget. Using ideas from Back Alley Coder's Element Resize Detector, font load detection can be done on any browser without resorting to setTimeout polling at a much smaller size.

Considerations

  • Several missing features in IE6, IE7, and IE8 necessitate the use of the legacy version of onfontready. IE9+ and all modern browsers can use standard onfontready. If IE8 or lower support is desired, use the legacy version.
  • Standard onfontready must create styled div and iframe elements. The legacy version of onfontready uses div, iframe, table, tbody, tr, and td tags. Any CSS styles applied via stylesheets or style tags that are applied globally to these elements, as well as any styles that directly influence page fonts (such as body { font-size: 0; }) may interfere with the font load detection. Please use CSS classes when specifying styling behavior for these elements to avoid incorrect detection.
  • onfontready takes steps to produce reasonable results even if the library is used incorrectly. However, IE6 and IE7 have several quirks when dealing with fallback fonts and generic font names that can cause some unintended results when using onfontready incorrectly. For full details, see the IE6 and IE7 notes in the Main Tests.

Known SVG Issue

A strange rendering bug can occur in Safari. This bug was the inspiration for the creation of onfontready.

In Safari, if...

  1. A font is switched at some critical moment during the page load process (such as with a font load detection library like onfontready), and
  2. The page contains inline SVGs that use remote SVG resources containing either SVG masks or SVG filters, and
  3. The remote reference SVG is positioned absolute or fixed, then
  4. The custom font may either render as invisible or as the fallback font until the next page repaint.

More details here. This can be mitigated by applying style="display:block;height:0" to the inline SVG tag acting as the remote SVG, rather than trying to absolutely position it.

Future Plans

  • Add ES module support once tooling becomes realistic.
  • Produce a new modern version specifically for browsers with ES6 (ES2015) native support as the world switches to those browsers.
  • Make note about the upcoming font-display feature, which can alleviate the need for much of onfontready in very new browsers.
  • Add support for ResizeObserver-based detection when it becomes more widely supported, using the iframe resize method as the fallback.
  • Investigate source-code permutation techniques to generate the smallest possible compressed sizes by mere rearrangement of order-independent code and alternate equivalent structures.

Package Sidebar

Install

npm i onfontready

Weekly Downloads

5

Version

1.1.0

License

MIT

Last publish

Collaborators

  • dwighthouse