onfontready v1.1.0
onfontready 1.1.0
Font load and parse detection with minimal size and maximum compatibility.
Features
- Can create sophisticated font loading experiences for pages, helping prevent FOIT or FOUT.
- Detects all known fonts including generic font families, zero-width fonts, and other weird fonts.
- Supports IE9+, Edge, Chrome, Firefox, Safari (+iOS), and Opera.
- Supports IE6+, Edge, Chrome, Firefox, Safari (+iOS), and Opera with
legacyversion. - 371 bytes gzipped (or 444 bytes for
legacy). More than 3.5 times smaller than FontFaceObserver. Fantastic for inlining! - Uses unopinionated callback-based architecture. Easily extended to other tools and architectures, like Promises with the Promise shim.
- Tons of Documentation and Examples.
- Available as a CommonJS module or window global.
- No dependencies or polyfills needed inside a browser context.
Install
Installation via NPM:
npm install --save onfontreadyInstallation via yarn:
yarn add onfontreadyPre-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.
Import the desired font.
Describe a
@font-facein 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">
Include
onfontready.Inline
onfontreadyat the bottom of the HTML (recommended).<html> ... <script> // From onfontready.min.js window.onfontready=...; </script> </html>Or use script src to import
onfontreadyat the bottom of the HTML.<html> ... <script src="dist/onfontready.min.js"></script> </html>Or include
onfontreadyinto Javascript codebase via CommonJS.var onfontready = require('onfontready');
Call
onfontreadywith 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"; } });Define actions to take upon successful load (
onReadyis called) and/or load failure (options.onTimeoutis called). In this pattern,fancyFontElementinitially 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-facedeclaration, 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 callingoptions.onTimeoutcallback.onfontreadywill wait indefinitely ifoptions.timeoutAfteris unset or 0. Negative numbers are allowed and act as a "fast" timeout.options.onTimeout- (function callback) Called afteroptions.timeoutAftermilliseconds have elapsed without anonReadycall.options.generic- (boolean) Causesonfontreadyto detect generic font families like fantasy, cursive, san-serif, or BlinkMacSystemFont if set totrue.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.
onfontreadydoes not attempt to initiate font loads itself via ajax as the CSS Font Loading API does.onfontreadydoes not feature Promise support, though Promise support can be added with a simple shim.onfontreadydoes not provide tools for loading or timing out fonts as a single unit, though multi-font support can be added using theonfontsreadyfunction.
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
legacyversion ofonfontready. IE9+ and all modern browsers can use standardonfontready. If IE8 or lower support is desired, use thelegacyversion. - Standard
onfontreadymust create styled div and iframe elements. Thelegacyversion ofonfontreadyuses 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 asbody { 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. onfontreadytakes 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 usingonfontreadyincorrectly. 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...
- A font is switched at some critical moment during the page load process (such as with a font load detection library like
onfontready), and - The page contains inline SVGs that use remote SVG resources containing either SVG masks or SVG filters, and
- The remote reference SVG is positioned absolute or fixed, then
- 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
onfontreadyin 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.