Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Patrick Hamann

April 24, 2017
Tweet

More Decks by Patrick Hamann

Other Decks in Technology

Transcript

  1. Name of Presentation
    CSS and the:
    First meaningful paint
    All Day Hey, April 2017

    Patrick Hamann
    @patrickhamann

    View full-size slide

  2. Name of Presentation
    Why?

    View full-size slide

  3. CSS and the first meaningful paint @patrickhamann
    How fast is your website?

    View full-size slide

  4. CSS and the first meaningful paint @patrickhamann
    What is the golden
    performance metric?

    View full-size slide

  5. CSS and the first meaningful paint @patrickhamann
    Does it even exist…
    Should it even exist?

    View full-size slide

  6. CSS and the first meaningful paint @patrickhamann
    How can we measure the
    perception and experience of
    our real users?

    View full-size slide

  7. CSS and the first meaningful paint
    • First byte

    • Document complete

    • Load event

    • Requests

    • Start render

    • SpeedIndex

    • First meaningful paint

    • Interactivity

    • Custom…

    Old New

    View full-size slide

  8. CSS and the first meaningful paint @patrickhamann
    WTF is TTFMP ?

    View full-size slide

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

    View full-size slide

  10. 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.

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  13. # of layout objects
    Timeline

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. https://www.webpagetest.org/
    Test on real devices
    Real network conditions

    View full-size slide

  19. 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?

    View full-size slide

  20. 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

    View full-size slide

  21. 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

    View full-size slide

  22. 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:

    View full-size slide

  23. 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

    View full-size slide

  24. Name of Presentation
    Baseline

    View full-size slide

  25. CSS and the first meaningful paint @patrickhamann
    1
    2
    3
    4
    5 FT.com
    6
    7
    8
    9 Other head elements...
    10
    11
    12
    13
    14 Content ...
    15
    16
    17

    View full-size slide

  26. CSS and the first meaningful paint @patrickhamann

    View full-size slide

  27. 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

    View full-size slide

  28. Name of Presentation
    Inline critical CSS

    View full-size slide

  29. 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

    View full-size slide

  30. 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

    View full-size slide

  31. 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

    View full-size slide

  32. 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

    View full-size slide

  33. ç
    https://github.com/filamentgroup/loadCSS
    1
    2
    3
    4
    5 FT.com
    6
    7 <br/>8 html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a{background-color:tran<br/>9<br/>10 Critical styles ...<br/>11
    12
    13
    14
    15 <br/>16 /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */<br/>17 (function(){ ... }());<br/>18
    19
    20 Other head elements...
    21
    22
    23
    24

    View full-size slide

  34. TCP slow-start https://hpbn.co/building-blocks-of-tcp/

    View full-size slide

  35. 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

    View full-size slide

  36. 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

    View full-size slide

  37. Name of Presentation
    Preload

    View full-size slide

  38. CSS and the first meaningful paint @patrickhamann
    What are your
    critical resources?

    View full-size slide

  39. Logo?
    Fonts?
    Hero image?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  42. 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

    View full-size slide

  43. 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

    View full-size slide

  44. 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

    View full-size slide

  45. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  48. https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  51. CSS and the first meaningful paint @patrickhamann
    Provides a declarative fetch primitive that
    initiates an early fetch and separates fetching
    from resource execution.

    View full-size slide

  52. CSS and the first meaningful paint @patrickhamann
    1
    2
    3
    4
    5 <br/>6 var res = document.createElement("link");<br/>7 res.rel = "preload";<br/>8 res.as = "style";<br/>9 res.href = "styles/other.css";<br/>10 document.head.appendChild(res);<br/>11
    1 Link: rel=“preload”; as=“style” nopush
    Preload with markup:
    Preload with HTTP header:

    View full-size slide

  53. 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: ; as=style; rel=preload; nopush, 

    ; rel=preload as=font crossorigin nopush,
    ; rel=preload as=font crossorigin nopush,
    ; as=image; rel=preload; nopush

    View full-size slide

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

    View full-size slide

  55. 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

    View full-size slide

  56. 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

    View full-size slide

  57. Name of Presentation
    Server push

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  67. CSS and the first meaningful paint @patrickhamann
    1
    2
    3
    4
    5 FT.com
    6
    7
    8
    9 ...
    10
    1 Link: ; 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

    View full-size slide

  68. Before
    index.html main.css
    Start render TTFMP
    Idle Idle

    View full-size slide

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

    View full-size slide

  70. 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

    View full-size slide

  71. CSS and the first meaningful paint @patrickhamann
    Is indicating push via the
    HTML response too late?

    View full-size slide

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

    View full-size slide

  73. 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

    View full-size slide

  74. CSS and the first meaningful paint
    • Easy to configure
    • Creates contention

    • Requires server logic

    • Hard to debug

    • Not cache aware
    Pros Cons

    View full-size slide

  75. Name of Presentation
    Asynchronous Push

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  86. 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

    View full-size slide

  87. 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);

    View full-size slide

  88. 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

    View full-size slide

  89. CSS and the first meaningful paint
    • Uses idle time

    • Ensures delivery before
    preload

    • Limited avaliablity

    • Custom server logic

    • Hard to debug
    Pros Cons

    View full-size slide

  90. CSS and the first meaningful paint @patrickhamann
    What about the
    repeat view?

    View full-size slide

  91. Name of Presentation
    Results

    View full-size slide

  92. Name of Presentation
    The future

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  97. Name of Presentation
    Conclusion

    View full-size slide

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

    View full-size slide

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

    under-utilised

    View full-size slide

  100. CSS and the first meaningful paint @patrickhamann
    Identify your critical resources
    and request chains.

    View full-size slide

  101. CSS and the first meaningful paint @patrickhamann
    Use preload to indicate critical
    resources, such as fonts to the
    browser.

    View full-size slide

  102. CSS and the first meaningful paint @patrickhamann
    Push critical CSS,
    but only on first view and only
    within idle time.

    View full-size slide

  103. CSS and the first meaningful paint @patrickhamann
    Always be testing.

    View full-size slide

  104. Name of Presentation
    Thanks!
    Patrick Hamann
    [email protected]
    @patrickhamann

    View full-size slide