The Performance and Usability of Font Loading (Velocity NYC 2015)

E1899004c71c7043343196103e210be3?s=47 zachleat
October 13, 2015

The Performance and Usability of Font Loading (Velocity NYC 2015)

A deep dive into @font-face for Velocity 2015 in New York City.

http://velocityconf.com/devops-web-performance-ny-2015/public/schedule/detail/46234

E1899004c71c7043343196103e210be3?s=128

zachleat

October 13, 2015
Tweet

Transcript

  1. The Performance and Usability of Web Fonts Zach Leatherman @zachleat

  2. @zachleat zachleat.com

  3. None
  4. N C T @

  5. N T O F C A F E @ -

  6. THE DEFAULT BROWSER BEHAVIOR FOR FONT-LOADING IS HARMFUL TO BOTH

    THE PERCEIVED PERFORMANCE AND INTEGRITY OF CONTENT ON THE WEB. FONT-LOADING INTEGRITY PERCEIVED PERFORMANCE
  7. 56% http://httparchive.org/trends.php OF WEB SITES

  8. http://httparchive.org/trends.php AVERAGE PAYLOAD 105KB

  9. 0 350 700 1050 1400 CSS javaScript Images WebFonts TRANSFER

    SIZE
  10. REMOVE AN IMAGE! JAVASCRIPT SIZE? WORRIED ABOUT

  11. NOT ALL REQUESTS ARE CREATED EQUAL

  12. PERCEIVED PERFORMANCE

  13. IMG

  14. CSS

  15. JavaScript

  16. WEB FONT

  17. A G EN D A TRIGGER A FONT DOWNLOAD BEHAVIOR

    WHILE DOWNLOADING 1.   2.  
  18. @font-­‐face  {    font-­‐family:  The  Font  that  Could;    src:

     url('icanfont.woff2')            format('woff2'),          url('icanfont.woff')            format('woff'),          url('icanfont.otf')            format('opentype');   }
  19. WOFF2 WOFF OTF SVG T 2.3–4.3

  20. WOFF2 WOFF

  21. IS 30% SMALLER THAN WOFF On average across all of

    Google Fonts: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/j27Ou4RtvQI/discussion WOFF2
  22. <!doctype  html>   <style>   @font-­‐face  {    font-­‐family:  My

     Web  Font;    src:  url('icanfont.woff2')  format('woff2'),        url('icanfont.woff')  format('woff');   }   </style>  
  23. None
  24. dAY since last pluralization ERROR 1

  25. dAY 0 since last pluralization ERROR

  26. IF NOT USED, NOT DOWNLOADED

  27. <p  style="font-­‐family:  My  Web  Font"></p> 9+

  28. <p  style="font-­‐family:  My  Web  Font">      Needs  Content.  

    </p>
  29. 8 36+ 23+ 6.1+ 2.3+ 7+ DOWNLOADS WITH EMPTY ATTACHED

    ELEMENT DOWNLOADS EVERY TIME DOWNLOADS WITH NON-EMPTY ATTACHED ELEMENT 28+ 9+ &
  30. RESTRICT TO SPECIFIC CHARACTERS

  31. unicode- range

  32. BASIC LATIN CODE POINTS Arial Chunk Five x26 & &

    x41 A A x42 B B x43 C C x2B + + x3F ? ?
  33. @font-­‐face  {     font-­‐family:  Ampersand;     src:  url('sands.woff2')

     format('woff2'),                url('sands.woff')  format('woff');      unicode-­‐range:  U+26;   } unicode- range
  34. <div  style="font-­‐family:   Ampersand">Needs  Content.</div>

  35. <div  style="font-­‐family:   Ampersand">Needs  an  &</div>

  36. Needs an _ FALLBACK Web Font

  37. unicode- range 36 9+ 23 8+ 2.1+ 8+ ALWAYS DOWNLOADS

    SMART DOWNLOAD NOT SUPPORTED &
  38. Matching Font-Family USED IN DOCUMENT CONTENT FONT-WEIGHT FONT-STYLE ✔ Images

    courtesy of http://www.w3.org/TR/css3-fonts/ ✔
  39. <!doctype  html>   <style>   @font-­‐face  {    font-­‐family:  My

     Web  Font;    src:  url('icanfont.woff2')  format('woff2'),        url('icanfont.woff')  format('woff');      font-­‐weight:  400;      font-­‐style:  normal;   }   </style>  
  40. <style>   p  {      font-­‐family:  My  Web  Font;

         font-­‐weight:  400;      font-­‐style:  normal;   }   </style>   <p>Roman  Text</p>
  41. @font-­‐face  {      font-­‐family:  My  Web  Font;    

     font-­‐weight:  400;      font-­‐style:  normal;   } p  {      font-­‐family:  My  Web  Font;      font-­‐weight:  400;      font-­‐style:  normal;   }
  42. @font-­‐face  {      font-­‐family:  My  Web  Font;    

     font-­‐weight:  400;      font-­‐style:  normal;   } p  {      font-­‐family:  My  Web  Font;      font-­‐weight:  400;      font-­‐style:  normal;   } ✔
  43. 100  200  300  400  500  600  700  800  900 FONT-WEIGHT

    DEFAULT  CSS   font-­‐weight:  normal; DEFAULT  CSS   font-­‐weight:  bold; ‐ ‑ ‑ ‐ Lighter  weights Bolder  weights
  44. @font-­‐face  {  font-­‐weight:  500;  font-­‐style:  normal;  }   @font-­‐face  {

     font-­‐weight:  400;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  300;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  200;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  100;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  600;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  700;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  800;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  900;  font-­‐style:  normal;  }   /*  REPEAT  THE  SAME,  WITH  font-­‐style:  italic;  */ p  {      font-­‐weight:  500;      font-­‐style:  normal;   }
  45. 100  200  300  400  500  600  700  800  900 FONT-WEIGHT

    <p> ‐ ‑ ‐ Lighter  weights Bolder  weights
  46. MisMatch weight 600 Available, 100 assigned, FORCED BOLD p  {

         font-­‐family:  My  Web  Font;      font-­‐weight:  100;      font-­‐style:  normal;   } @font-­‐face  {      font-­‐family:  My  Web  Font;      font-­‐weight:  600;      font-­‐style:  normal;   }
  47. MISMATCH STYLE ITALIC AVAILABLE, NORMAL ASSIGNED, FORCED ITALIC p  {

         font-­‐family:  My  Web  Font;      font-­‐weight:  400;      font-­‐style:  normal;   } @font-­‐face  {      font-­‐family:  My  Web  Font;      font-­‐weight:  400;      font-­‐style:  italic;   }
  48. @font-­‐face  {  font-­‐weight:  600;  font-­‐style:  normal;  }   @font-­‐face  {

     font-­‐weight:  700;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  800;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  900;  font-­‐style:  normal;  }   /*  FAUX  BOLD  */   @font-­‐face  {  font-­‐weight:  500;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  400;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  300;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  200;  font-­‐style:  normal;  }   @font-­‐face  {  font-­‐weight:  100;  font-­‐style:  normal;  }   /*  END  FAUX  BOLD  */   /*  REPEAT  THE  SAME,  WITH  font-­‐style:  italic;  */ p  {      font-­‐weight:  600;      font-­‐style:  normal;   }
  49. 100  200  300  400  500  600  700  800  900 FONT-WEIGHT

    <p> ‐ ‑ ‐ Normal/Roman  @font-­‐face Bold  @font-­‐face Faux  Bold
  50. MisMatch weight 500 Available, 600 assigned, FAUX BOLD p  {

         font-­‐family:  My  Web  Font;      font-­‐weight:  600;      font-­‐style:  normal;   } @font-­‐face  {      font-­‐family:  My  Web  Font;      font-­‐weight:  500;      font-­‐style:  normal;   }
  51. MISMATCH STYLE p  {      font-­‐family:  My  Web  Font;

         font-­‐weight:  400;      font-­‐style:  italic;   } @font-­‐face  {      font-­‐family:  My  Web  Font;      font-­‐weight:  400;      font-­‐style:  normal;   } NORMAL AVAILABLE, ITALIC ASSIGNED, FAUX ITALIC
  52. DISABLE FAUX FONTS WITH FONT-SYNTHESIS

  53. None
  54. http://stateofwebtype.com/ STATE OF WEB TYPE

  55. <style>   @font-­‐face  {      font-­‐weight:  400;    

     font-­‐style:  normal;   }   </style>   <p>      Roman  Text      <strong>Bold  Text</strong>      <b>Bold  Text</b>      <em>Italic  Text</em>      <i>Italic  Text</i>   </p>
  56. BE FRUGAL BE

  57. BE FRUGAL BUT NOT TOO

  58. instagram.com 6 @font-face BLOCKS

  59. None
  60. None
  61. None
  62. None
  63. None
  64. <i>

  65. .page-­‐home  .content  .home-­‐login  i  {      font-­‐style:  normal;  

    }
  66. SAVES 13.4KB FOR EACH EMPTY-CACHE PAGELOAD TO INSTAGRAM.COM

  67. i,  cite,  em,  var,   address,  dfn,   strong,  b,

     h1,  h2,   h3,  h4,  h5,  h6,  th
  68. Matching Font-Family USED IN DOCUMENT CONTENT FONT-WEIGHT FONT-STYLE ✔ Images

    courtesy of http://www.w3.org/TR/css3-fonts/ ✔ ✔ ✔
  69. A G EN D A TRIGGER A FONT DOWNLOAD BEHAVIOR

    WHILE DOWNLOADING 1.   2.  
  70. FONT FINISHES LOADING A B FONT IS USED, STARTS LOADING

    @FONT-FACE IS PARSED
  71. FONT FINISHES LOADING A B FONT IS USED, STARTS LOADING

    @FONT-FACE IS PARSED
  72. LOCAL FONT { @FONT-FACE { A B

  73. Flash of Invisible Text F O I T

  74. FOIT

  75. http://www.webpagetest.org/video/compare.php?tests=141205_VE_STK-r:1-c:0

  76. http://www.webpagetest.org/video/compare.php?tests=141205_VE_STK-r:1-c:0

  77. People will visit a Web site less often if it

    is slower than a close competitor by more than 250 milliseconds.” http://www.nytimes.com/2012/03/01/technology/impatient-web-users-flee-slow-loading-sites.html “
  78. None
  79. None
  80. None
  81. https://twitter.com/zoompf/status/578901383253995520

  82. http://www.webpagetest.org/video/compare.php?tests=141209_AY_Z79-r:1-c:0

  83. http://www.webpagetest.org/video/compare.php?tests=141209_AY_Z79-r:1-c:0

  84. http://www.webpagetest.org/video/compare.php?tests=141209_AY_Z79-r:1-c:0

  85. LOCAL FONT { @FONT-FACE { A 3s B

  86. Flash of UNSTYLED Text F O U T

  87. FOUT

  88. IS 3 SECONDS A GOOD TIMEOUT?

  89. https://twitter.com/zoompf/status/578901383253995520

  90. NOT JUST A PERFORMANCE PROBLEM

  91. https://twitter.com/jmuspratt/status/561239961924403200

  92. https://twitter.com/jmuspratt/status/561239961924403200

  93. https://twitter.com/jmuspratt/status/561239961924403200

  94. None
  95. None
  96. LOCAL FONT { @FONT-FACE {

  97. FOUT FOIT REVIEW

  98. FOIT

  99. ABCDEFGH FOIT @FONT-FACE LOAD

  100. FOIT to FOUT, 3 seconds

  101. 3 S ABCDEFGH FOIT to FOUT, 3 seconds

  102. 3 S ABCDEFGH FOIT to FOUT, 3 seconds @FONT-FACE LOAD

  103. FOUT, 0 seconds ABCDEFGH

  104. ABCDEFGH FOUT, 0 seconds @FONT-FACE LOAD

  105. “But FOUT is ugly.”

  106. PNG BASELINE JPEG Progressive JPEG

  107. WebPageTest.org

  108. SOLUTION CONTINUUM

  109. FOUT DO NOTHING EMBRACE BROWSER DEFAULTS 0 SECOND TIMEOUT FOUT

    FOIT N SECOND TIMEOUT FOIT InFINITE TIMEOUT N  >  0
  110. DO NOTHING EMBRACE BROWSER DEFAULTS FOIT InFINITE TIMEOUT FONT REQUESTs

    ARE A SINGLE POINT OF FAILURE
  111. STOP BUTTON HAS NO EFFECT

  112. ANTI- PATTERNS

  113. CSS ONLOAD

  114. <style>   h1  {  font-­‐family:  serif;  }   .loaded  h1

     {  font-­‐family:  My  Web  Font;  }   </style>   <link  href="fonts.css"   onload="document.body.className+='   loaded';"  rel="stylesheet">  
  115. @font-­‐face  {      font-­‐family:  My  Web  Font;    

     src:  url('icanfont.woff')  format('woff');   }   @font-­‐face  {      font-­‐family:  My  Web  Font;      src:  url('icanfontbold.woff')  format('woff');      font-­‐weight:  700;   }
  116. BLOCKING FONTS.CSS Blocking FONT REQUESTS

  117. BLOCKING FONTS.CSS Blocking FONT REQUESTS A Fonts   start  

    loading
  118. BLOCKING FONTS.CSS Blocking FONT REQUESTS onload Fonts   finish  

    loading B A Fonts   start   loading
  119. ASYNC- CSS

  120. <style>   h1  {  font-­‐family:  serif;  }   .loaded  h1

     {  font-­‐family:  My  Web  Font;  }   </style>   <link  href="fonts.css"  media="none"   onload="document.body.className+='   loaded';  this.media='all'"   rel="stylesheet">  
  121. BLOCKING FONTS.CSS

  122. ASYNC FONTS.CSS

  123. ASYNC FONTS.CSS Blocking FONT REQUESTS onload Fonts   finish  

    loading B A Fonts   start   loading
  124. filamentgroup / loadcss https://github.com/filamentgroup/loadCSS

  125. ASYNC- CSS with DATA URIS

  126. @font-­‐face  {      font-­‐family:  My  Web  Font;    

     src:  url('data:application/x-­‐font-­‐ woff;charset=utf-­‐8;base64,...')  format('woff');   }   @font-­‐face  {      font-­‐family:  My  Web  Font;      src:  url('data:application/x-­‐font-­‐ woff;charset=utf-­‐8;base64,...')  format('woff');      font-­‐weight:  700;   }
  127. ASYNC FONTS.CSS Font  Data  URIs   finish   loading B

    A Font  Data  URIs   start   loading REPAINT
  128. None
  129. None
  130. INLINE DATA URIS WITH MAIN CSS

  131. None
  132. ONE 50KB CSS REQUEST NO FONT REQUESTS

  133. @font-­‐face  {      font-­‐family:  Roboto;      src:  url('data:application/x-­‐font-­‐

    woff;charset=utf-­‐8;base64,...')  format('woff');   }   @font-­‐face  {      font-­‐family:  Roboto;      src:  url('data:application/x-­‐font-­‐ woff;charset=utf-­‐8;base64,...')  format('woff');      font-­‐weight:  700;   }
  134. FOUT 0 SECOND TIMEOUT FOUT FOIT N SECOND TIMEOUT N

     >  0 EMBRACE MORE FOUT
  135. font-DISPLAY CSS DESCRIPTOR https://tabatkins.github.io/specs/css-font-display/ from Kenji Baheux, Tab Atkins

  136. CSS Font Loading http://dev.w3.org/csswg/css-font-loading/

  137. FONTFACEONLOAD github.com/zachleat/fontfaceonload USES THE CSS FONT LOADING API WHEN AVAILABLE.

    FONTFACEOBSERVER github.com/bramstein/fontfaceobserver/ INCLUDES A NICE PROMISES POLYFILL
  138. 0 SECOND TIMEOUT FOUT

  139. var  doc  =  document,          docEl  =

     doc.documentElement;   doc.fonts.load("1em  Raleway")    .then(function()  {          //  The  font  has  loaded.      docEl.className  +=  "  raleway-­‐loaded";    }); ‑
  140. body  {      font-­‐family:  sans-­‐serif;   }   .raleway-­‐loaded

     body  {      font-­‐family:  Raleway,  sans-­‐serif;   } ‑
  141. FONT REQUEST REPAINT Font   finishes   loading B A

    Font   starts   loading
  142. FOUT RALEWAY font-­‐display:  swap;

  143. FOUT @FONT-FACE LOAD font-­‐display:  swap;

  144. FOUT FOIT N SECOND TIMEOUT N  >  0

  145. var  docEl  =  document.documentElement;   docEl.className  +=  "  raleway-­‐loading";  

    window.setTimeout(function()  {      docEl.className  +=  "  raleway-­‐fallback";   },  1000);   document.fonts.load("1em  Raleway").then(function()  {      docEl.className  +=  "  raleway-­‐loaded";   });   ‑
  146. .raleway-­‐loading  body  {      color:  transparent;   }  

    .raleway-­‐fallback  body,   .raleway-­‐loaded  body  {      color:  inherit;   }   .raleway-­‐fallback  body  {      font-­‐family:  serif;   }   .raleway-­‐loaded  body  {      font-­‐family:  Raleway,  serif;   } ‑
  147. FOIT to FOUT, 1 second

  148. 1 S FOIT to FOUT, 1 second RALEWAY

  149. 1 S FOIT to FOUT, 1 second @FONT-FACE LOAD

  150. https://twitter.com/jmuspratt/status/561239961924403200

  151. ONE REPAINT TO RULE THEM ALL

  152. Promise.all([      document.fonts.load("400  1em  Raleway"),      document.fonts.load("700  1em

     Raleway")   ]).then(function  ()  {      docEl.className  +=  "  raleway-­‐loaded";   }); ‑ document.fonts.load("1em  Raleway").then(function()  {      docEl.className  +=  "  raleway-­‐loaded";   }); BECOMES
  153. FONT REQUESTS

  154. FONT REQUESTS REPAINT Fonts   finish   loading B A

    Fonts   start   loading
  155. TWO REPAINTS TO RULE THEM ALL

  156. MOST  JARRING   REPAINT  FOR  ROMAN ROMAN

  157. MOST  JARRING   REPAINT  FOR  ROMAN BOLD ITALIC BOLD  ITALIC

    ROMAN
  158. MOST  JARRING   REPAINT  FOR  ROMAN BOLD ITALIC BOLD  ITALIC

    FAUX   VERSIONS ROMAN
  159. MOST  JARRING   REPAINT  FOR  ROMAN BOLD ITALIC BOLD  ITALIC

    FAUX   VERSIONS FINAL  REPAINT ROMAN
  160. ARIAL ARIAL BOLD

  161. EXO EXO FAUX BOLD

  162. EXO EXO BOLD

  163. FLASH OF FAUX TEXT zachleat.com/web/foft/

  164. FALLBACKS ARE IMPORTANT

  165. None
  166. None
  167. fontfamily.io

  168. MINIMIZE THE FALLBACK to WEBFONT REFLOW

  169. font-­‐family   FALLBACK STYLE font-­‐size   font-­‐size-­‐adjust   line-­‐height

  170. Web Font Tune-up Time: A Fun Font Fallback Event http://blog.fonts.com/2011/08/web-font-tune-up-

    time-a-fun-font-fallback-event/
  171. None
  172. None
  173. THERE ARE A LOT OF TOOLS AT OUR DISPOSAL TO

    EASE THE TRANSITION FROM FALLBACK TO WEBFONT
  174. THE DEFAULT BROWSER BEHAVIOR FOR FONT-LOADING IS HARMFUL TO BOTH

    THE PERCEIVED PERFORMANCE AND INTEGRITY OF CONTENT ON THE WEB. FONT-LOADING INTEGRITY PERCEIVED PERFORMANCE
  175. USE A FONT LOADING STRATEGY.

  176. DON’t ACCEPT THE DEFAULTS.

  177. @zachleat zachleat.com