CSS and the First Meaningful Paint - All day Hey!, April 2017

CSS and the First Meaningful Paint - All day Hey!, April 2017

To render a webpage browsers needs to go through the complex dance of networking, parsing and painting before any content can be displayed to your user. Over the years, we've developed mechanisms and hacks to aid the browser at each stage of this process, but these have always come at some cost or trade-off.

How can we utilize modern web platform features to load our CSS as fast as possible? Should we still be inlining our critical content into the document or instead, how can HTTP/2 server push and Service Workers help us?

In this talk we will take a journey exploring the current, past, and future best-practices for loading CSS in the browser and how we can achieve a first meaningful paint within 1000ms. Ultimately creating a faster, more resilient experience for our users.

276c149f793de9af4e98991ed52ff874?s=128

Patrick Hamann

April 24, 2017
Tweet

Transcript

  1. Name of Presentation CSS and the: First meaningful paint All

    Day Hey, April 2017
 Patrick Hamann @patrickhamann
  2. None
  3. Name of Presentation Why?

  4. CSS and the first meaningful paint @patrickhamann How fast is

    your website?
  5. CSS and the first meaningful paint @patrickhamann What is the

    golden performance metric?
  6. CSS and the first meaningful paint @patrickhamann Does it even

    exist… Should it even exist?
  7. CSS and the first meaningful paint @patrickhamann How can we

    measure the perception and experience of our real users?
  8. CSS and the first meaningful paint • First byte •

    Document complete • Load event • Requests • Start render • SpeedIndex • First meaningful paint • Interactivity • Custom… Old New
  9. CSS and the first meaningful paint @patrickhamann WTF is TTFMP

    ?
  10. CSS and the first meaningful paint @patrickhamann First Meaningful Paint

    is the time when a page’s primary content appeared on the screen.
  11. CSS and the first meaningful paint @patrickhamann First Meaningful Paint

    is the first paint after which the biggest above-the-fold layout change has happened, and web fonts have loaded.
  12. CSS and the first meaningful paint @patrickhamann A bold statement

  13. https://docs.google.com/document/d/1BR94tJdZLsin5poeet0XoTW60M0SjvOJQttKT-JK8HI

  14. # of layout objects Timeline

  15. CSS and the first meaningful paint @patrickhamann A bold statement

  16. CSS and the first meaningful paint @patrickhamann A bold statement

  17. https://developers.google.com/web/tools/lighthouse/

  18. Name of Presentation Optimising for TTFMP A case-study: FT.com

  19. None
  20. https://www.webpagetest.org/ Test on real devices Real network conditions

  21. CSS and the first meaningful paint @patrickhamann • Where are

    your users based? • What is your device landscape? • In what context are they using your site? • What is their network profile? • What did they come for? What is your average user profile?
  22. CSS and the first meaningful paint @patrickhamann The average load

    time for mobile sites is 19 seconds over 3G connections The need for mobile speed, Google DoubleClick
  23. CSS and the first meaningful paint @patrickhamann 53% of mobile

    site visits are abandoned if pages takes longer than 3 seconds to load. The need for mobile speed, Google DoubleClick
  24. None
  25. CSS and the first meaningful paint @patrickhamann Forming a TTFMP

    baseline: 3G EM 3G Cable 3 secs 2 secs 1 secs Time to First Meaningful Paint: 3G EM 3G Cable ? ? ? Insert your custom profiles here:
  26. CSS and the first meaningful paint @patrickhamann Case-study profile: BW

    down BW up Latency RTT 3G EM 400 kbs 400 kbs 400 ms 3G 1.6 Mbs 768 kbs 150 ms Cable 5m Mbs 1Mbs 28 ms • Moto G (low-mid Android) • 9 runs • Chrome beta
  27. Name of Presentation Baseline

  28. CSS and the first meaningful paint @patrickhamann 1 <!DOCTYPE html>

    2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>FT.com</title> 6 7 <link rel="stylesheet" href="main.css" /> 8 9 Other head elements... 10 11 </head> 12 <body> 13 14 Content ... 15 16 </body> 17 </html>
  29. CSS and the first meaningful paint @patrickhamann

  30. Name of Presentation Baseline results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline 3G EM 3G Cable TTFMP % impovement 3G EM 3259 63 3G 1462 63 Cable 1327 46
  31. Name of Presentation Inline critical CSS

  32. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css GET js response response idle idle Render blocking Run JS Async
  33. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css GET js response response idle idle Render blocking Run JS Async
  34. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css GET js response response idle idle Render blocking Run JS Async GET css response
  35. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css response idle Async Render
  36. None
  37. ! !

  38. ç https://github.com/filamentgroup/loadCSS 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head>

    4 <meta charset="UTF-8"> 5 <title>FT.com</title> 6 7 <style> 8 html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a{background-color:tran 9 10 Critical styles ... 11 </style> 12 13 <link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'"> 14 <noscript><link rel="stylesheet" href="main.css"></noscript> 15 <script> 16 /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ 17 (function(){ ... }()); 18 </script> 19 20 Other head elements... 21 22 </head> 23 <body> 24
  39. TCP slow-start https://hpbn.co/building-blocks-of-tcp/

  40. Before

  41. After

  42. After

  43. Name of Presentation Inline critical CSS results TTFMP (ms) 0

    1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 3259 63 3G 1462 63 Cable 1327 46
  44. CSS and the first meaningful paint • No blocking resources

    • No SPOF on CSS • Less requests over wire • Instant painting • Causes reflow • Not cachable • Hard to maintain • Hard to automate Pros Cons
  45. Name of Presentation Preload

  46. CSS and the first meaningful paint @patrickhamann What are your

    critical resources?
  47. Logo? Fonts? Hero image?

  48. Lighthouse https://developers.google.com/web/tools/lighthouse/

  49. Lighthouse https://developers.google.com/web/tools/lighthouse/

  50. Before

  51. Before

  52. CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint HTML DOM CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  53. CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint HTML CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  54. CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint HTML CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  55. CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  56. CSS and the first meaningful paint @patrickhamann JavaScript Render tree

    Layout Paint CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  57. CSS and the first meaningful paint @patrickhamann Render tree Layout

    Paint Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  58. https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model

  59. CSS and the first meaningful paint @patrickhamann The preload scanner

  60. Preload, W3C working draft https://www.w3.org/TR/preload/

  61. CSS and the first meaningful paint @patrickhamann Provides a declarative

    fetch primitive that initiates an early fetch and separates fetching from resource execution.
  62. CSS and the first meaningful paint @patrickhamann 1 <!-- preload

    stylesheet resource via declarative markup --> 2 <link rel="preload" href="/styles/other.css" as="style"> 3 4 <!-- or, preload stylesheet resource via JavaScript --> 5 <script> 6 var res = document.createElement("link"); 7 res.rel = "preload"; 8 res.as = "style"; 9 res.href = "styles/other.css"; 10 document.head.appendChild(res); 11 </script> 1 Link: </styles/other.css> rel=“preload”; as=“style” nopush Preload with markup: Preload with HTTP header:
  63. CSS and the first meaningful paint @patrickhamann < GET /index.html


    
 < HTTP/1.1 200 OK < Cache-Control: private, max-age=60, must-revalidate < Expires: Thu, 20 Apr 2017 21:39:52 GMT < Last-Modified: Thu, 20 Apr 2017 13:11:33 GMT < ETag: "966eca3815d88d8848933d33c68ab2bd" < Content-Type: text/html < Content-Encoding: gzip < Content-Length: 43177 < Date: Thu, 20 Apr 2017 21:39:52 GMT < Connection: keep-alive < Link: <main.css>; as=style; rel=preload; nopush, 
 <MetricWeb-Regular.woff>; rel=preload as=font crossorigin nopush, <MetricWeb-Semibold.woff>; rel=preload as=font crossorigin nopush, <ftlogo.svg>; as=image; rel=preload; nopush
  64. Before

  65. Before

  66. After

  67. Preload browser support, April 2017, http://caniuse.com/#feat=link-rel-preload

  68. Name of Presentation Preload results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline Preload 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 3176 64 3G 1778 55 Cable 1042 57
  69. CSS and the first meaningful paint • Indicate hidden resources

    • Dictate priority and order • Separates fetch from exec • Easy to create contention • Requires server logic Pros Cons
  70. Name of Presentation Server push

  71. CSS and the first meaningful paint @patrickhamann HTTP/2

  72. CSS and the first meaningful paint @patrickhamann " # Client

    Server
  73. CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html
  74. CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html 200 OK /index.html
  75. CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html GET /main.css 200 OK /index.html
  76. CSS and the first meaningful paint @patrickhamann " # Client

    Server
  77. CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html
  78. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css GET /index.html
  79. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css 200 OK /index.html GET /index.html
  80. CSS and the first meaningful paint @patrickhamann 1 <!DOCTYPE html>

    2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>FT.com</title> 6 7 <link rel="stylesheet" href="critical.css" /> 8 <link rel="preload" href="main.css" as="style" onload=“this.rel='stylesheet'" /> 9 ... 10 1 Link: <critical.css>; rel=“preload”; as=“style” Indicate push of critical styles with Link preload header: Convert inline styles into normal link rel=“stylesheet” declaration and async the main styles
  81. Before index.html main.css Start render TTFMP Idle Idle

  82. TTFMP Start render After critical.css TTFMP index.html main.css Idle Start

    render Idle
  83. CSS and the first meaningful paint @patrickhamann /hero.jpg Stream ID:

    4 Weight: 16 /data.json Stream ID: 7 Weight: 16 /app.js Stream ID: 3 Weight: 64 /icon.svg Stream ID: 9 Weight: 16 /main.css Stream ID: 2 Weight: 110 /index.html Stream ID: 1 Weight: 128
  84. CSS and the first meaningful paint @patrickhamann Is indicating push

    via the HTML response too late?
  85. After

  86. After

  87. HTTP/2 browser support, April 2017, http://caniuse.com/#feat=http2

  88. Name of Presentation Push results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline Preload Push 1256 1042 1327 2477 2826 1778 1462 3983 5035 3176 3259 8849 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 5035 43 3G 2826 29 Cable 1256 49
  89. CSS and the first meaningful paint • Easy to configure

    • Creates contention • Requires server logic • Hard to debug • Not cache aware Pros Cons
  90. Name of Presentation Asynchronous Push

  91. TTFMP Start render After critical.css TTFMP index.html main.css Idle Start

    render Idle
  92. TTFMP Start render After critical.css TTFMP index.html main.css Idle Start

    render Idle
  93. CSS and the first meaningful paint @patrickhamann " # Client

    Server HTTP/2 connection
  94. CSS and the first meaningful paint @patrickhamann " # Client

    Server HTTP/2 connection GET /index.html
  95. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css $ HTTP/2 connection GET /index.html
  96. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css 200 OK /index.html HTTP/2 connection GET /index.html
  97. CSS and the first meaningful paint @patrickhamann " # Client

    Server " App
  98. CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html " GET /index.html App
  99. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css - GET /index.html " GET /index.html App
  100. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css - $ GET /index.html " GET /index.html App
  101. CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css - $ 200 OK /index.html GET /index.html " GET /index.html 200 OK /index.html App
  102. CSS and the first meaningful paint @patrickhamann 1 const http2

    = require('http2'); 2 3 function handler(request, response) { 4 if (request.url === "/index.html") { 5 const push = response.push('/critical.css'); 6 push.writeHead(200); 7 fs.createReadStream('/critical.css').pipe(push); 8 } 9 10 // Generate index response: 11 // - Fetch data from DB 12 // - Render template 13 // etc ... 14 15 response.end(data); 16 } 17 18 const server = http2.createServer(opts, handler); 19 server.listen(80);
  103. Before

  104. After

  105. Name of Presentation Push async results TTFMP (ms) 0 1000

    2000 3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline Preload Push Push async 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 3062 65 3G 1613 59 Cable 1021 58
  106. CSS and the first meaningful paint • Uses idle time

    • Ensures delivery before preload • Limited avaliablity • Custom server logic • Hard to debug Pros Cons
  107. CSS and the first meaningful paint @patrickhamann What about the

    repeat view?
  108. Name of Presentation Results

  109. None
  110. None
  111. None
  112. None
  113. Name of Presentation The future

  114. Cache digests for HTTP/2, K. Oku https://tools.ietf.org/html/draft-ietf-httpbis-cache-digest-01

  115. https://www.ietf.org/proceedings/95/slides/slides-95-httpbis-5.pdf

  116. Early hints status code for HTTP, K. Oku https://tools.ietf.org/html/draft-ietf-httpbis-early-hints-01

  117. https://www.ietf.org/proceedings/97/slides/slides-97-httpbis-sessb-early-hints-00.pdf

  118. Name of Presentation Conclusion

  119. CSS and the first meaningful paint @patrickhamann Resource loading is

    hard.
  120. CSS and the first meaningful paint @patrickhamann Bandwidth is often

    
 under-utilised
  121. CSS and the first meaningful paint @patrickhamann Identify your critical

    resources and request chains.
  122. CSS and the first meaningful paint @patrickhamann Use preload to

    indicate critical resources, such as fonts to the browser.
  123. CSS and the first meaningful paint @patrickhamann Push critical CSS,

    but only on first view and only within idle time.
  124. CSS and the first meaningful paint @patrickhamann Always be testing.

  125. Name of Presentation Thanks! Patrick Hamann patrick@fastly.com @patrickhamann