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

CSS and the First Meaningful Paint - CSS Conf EU, May 2017

CSS and the First Meaningful Paint - CSS Conf EU, May 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

May 06, 2017
Tweet

More Decks by Patrick Hamann

Other Decks in Technology

Transcript

  1. CSS and the:
    First meaningful paint
    CSS Conf EU, May 2017
    Patrick Hamann
    @patrickhamann

    View Slide

  2. View Slide

  3. Why?

    View Slide

  4. CSS and the first meaningful paint @patrickhamann
    How do you measure your
    performance?

    View Slide

  5. CSS and the first meaningful paint
    • First byte

    • Document complete

    • Load event

    • Requests / bytes

    • Start render

    • SpeedIndex

    • First meaningful paint

    • Time to Interactivity

    • Custom…

    Old New

    View Slide

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

    View Slide

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

    View Slide

  8. 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 Slide

  9. https://docs.google.com/document/d/1BR94tJdZLsin5poeet0XoTW60M0SjvOJQttKT-JK8HI
    # of layout objects
    Timeline

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. Optimising for TTFMP
    A case-study: FT.com

    View Slide

  14. View Slide

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

    View Slide

  16. CSS and the first meaningful paint @patrickhamann
    • Where are your users based?
    • What is their 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 Slide

  17. 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 Slide

  18. Baseline

    View Slide

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

  20. CSS and the first meaningful paint @patrickhamann

    View Slide

  21. Name of Presentation
    Baseline results
    TTFMP (ms)
    0
    1000
    2000
    3000
    4000
    5000
    6000
    7000
    8000
    9000
    10000
    Baseline
    3G EM 3G Cable

    View Slide

  22. Inline critical CSS

    View Slide

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

    View Slide

  24. 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 JS

    View Slide

  25. 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 JS
    GET css response

    View Slide

  26. 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 CSS
    Render

    View Slide

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

  28. Before

    View Slide

  29. Before

    View Slide

  30. After

    View Slide

  31. After

    View Slide

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

  33. CSS and the first meaningful paint
    • No blocking resources

    • No SPOF on CSS

    • Eliminates critical request

    • Instant painting

    • Causes reflow

    • Not cachable
    • Hard to maintain

    • Hard to automate
    Pros Cons

    View Slide

  34. Preload

    View Slide

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

    View Slide

  36. Logo?
    Fonts?
    Hero image?

    View Slide

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

    View Slide

  38. Before

    View Slide

  39. CSS and the first meaningful paint @patrickhamann
    Request page
    Network
    Renderer
    GET html
    Build DOM
    response
    Build CSSOM First paint
    GET css response
    idle idle
    Render blocking
    Render tree

    View Slide

  40. CSS and the first meaningful paint @patrickhamann
    Request page
    Network
    Renderer
    GET html
    Build DOM
    response
    Build CSSOM First paint
    GET css response
    idle idle
    Render blocking
    GET font response
    Text paint
    Text blocking
    Render tree

    View Slide

  41. CSS and the first meaningful paint @patrickhamann
    Request page
    Network
    Renderer
    GET html
    Build DOM
    response
    Build CSSOM First paint
    GET css response
    idle idle
    Render blocking
    GET font response
    Text paint
    Text blocking
    Render tree

    View Slide

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

    View Slide

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

    View Slide

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

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

  46. Before

    View Slide

  47. After

    View Slide

  48. 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 Slide

  49. 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 Slide

  50. Server push

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  54. 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 Slide

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

    View Slide

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

    View Slide

  57. 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 Slide

  58. Result

    View Slide

  59. 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 Slide

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

    View Slide

  61. Async push

    View Slide

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

    View Slide

  63. 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 Slide

  64. 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 Slide

  65. After

    View Slide

  66. 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 Slide

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

    • Ensures delivery before
    preload

    • Easy to create contention

    • Limited avaliablity

    • Custom server logic

    • Hard to debug
    Pros Cons

    View Slide

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

    View Slide

  69. CSS and the first meaningful paint @patrickhamann
    PRPL

    View Slide

  70. Result

    View Slide

  71. View Slide

  72. The future

    View Slide

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

    View Slide

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

    View Slide

  75. Conclusion

    View Slide

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

    View Slide

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

    under-utilised

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  82. Thanks!
    Patrick Hamann
    [email protected]
    @patrickhamann

    View Slide