CSS Performance Tooling

96270e4c3e5e9806cf7245475c00b275?s=47 Addy Osmani
September 13, 2014

CSS Performance Tooling

Presented at CSSConf.eu, September 2014.

Video: https://www.youtube.com/watch?v=FEs2jgZBaQA

You've learned the concepts, now meet the tools. High-performance sites need to feel instant and deliver the goods in

96270e4c3e5e9806cf7245475c00b275?s=128

Addy Osmani

September 13, 2014
Tweet

Transcript

  1. 2.

    When you want to be fast, you have to give

    up the things slowing you down.
  2. 4.

    3 Tiers Of Optimization Tooling 1. Baseline ◦ Minification, Concatenation,

    Image optimization, Compression (GZip, Zopfli), Async scripts, Leverage caching, WOFF2 for fonts, Spriting. Avoid redirects. 2. Get fast, stay fast. ◦ Inlining critical CSS, deferring non-critical assets to avoid render blocking, removing unused CSS, visual regression testing to verify changes. Performance benchmarking. 3. Nice to haves ◦ Reduce duplicate colors, selectors, font-families, sizes.
  3. 15.

    https://sites.google.com/a/webpagetest.org/docs/using- webpagetest/metrics/speed-index The average time at which visible parts of

    the page are displayed. Expressed in milliseconds and dependent on size of the viewport. Speed Index
  4. 18.
  5. 20.
  6. 24.
  7. 25.
  8. 27.
  9. 35.
  10. 39.
  11. 40.
  12. 41.
  13. 43.
  14. 44.
  15. 47.
  16. 48.

    HTML CSS DOM CSSOM Render Tree Layout Paint Network Deliver

    only the goods that will be used Hello • Wrong way to think about unused CSS ◦ “I just want to ship the CSS for current page” ◦ “I’m going to ignore styles used in other pages” • Right way ◦ What site-wide CSS am I shipping that is not used by any pages?
  17. 53.
  18. 54.

    Removing unused CSS Load files and execute JavaScript Extract Stylesheets

    from HTML Filter out selectors not found in HTML PhantomJS css-parse Stylesheets concatenated & parsed Remaining rules converted back to CSS
  19. 55.
  20. 56.

    uncss: { dist: { options: { ignore : ['#added_at_runtime', /test\-[0-9]+/],

    media : ['(min-width: 700px) handheld and (orientation: landscape)'], csspath : '../public/css/', raw : 'h1 { color: green }', stylesheets : ['lib/bootstrap/dist/css/bootstrap.css', 'src/public/css/main.css'], ignoreSheets : [/fonts.googleapis/], urls : ['http://localhost:3000/mypage', '...'], // Deprecated timeout : 1000, htmlroot : 'public', report : 'min' }, files: { 'dist/css/tidy.css': ['app/index.html', 'app/about.html'] } } } Gruntfile.js
  21. 57.

    uncss: { dist: { files: { '_site/stylesheets/screen.css': [ '_site/index.html', '_site/sponsors.html',

    'site/_news.html', '_site/schedule.html', '_site/speakers/index.html', ... JSConf Gruntfile.js Include ALL site URLs
  22. 58.

    UnCSS as a post-processor HTML, JavaScript Sass Minified HTML CSS

    UnCSS Minify Done Source Minified JavaScript Works with Sass, Less, Stylus
  23. 59.

    Sizing up the average Bootstrap page MINIFIED ORIGINAL STYLES UNCSS

    + MINIFICATION 120KB 110KB 11KB (1) ~ 90% improvement (2) Based on average improvements reported by UnCSS users
  24. 60.
  25. 61.

    Sizing up JSConf.eu styles MINIFIED ORIGINAL STYLES UNCSS + MINIFICATION

    20KB 11KB 7KB (1) > 50% improvement on minification. Worth it? Questionable. (2) UnCSS is most useful when using a CSS library or have a large site
  26. 63.

    Warnings We cannot identify with 100% certainty all the CSS

    that you still need for your site, since it's likely to be missing some CSS that you will actually need in some cases. Dynamically injected styles are supported, but have many edge-cases where they may lead to inaccurate removals of CSS. When removing unused CSS, don’t guess it. Test it.
  27. 66.
  28. 67.

    Why care about it? It’s useful Regressions in your UI

    can be hard to identify Cost of manual testing gets higher with responsive layouts Can drive tests with fake data if needed Solution Visual regression tooling + Resemble.js
  29. 68.

    npm install phantomcss Install grunt.initConfig({ 'phantomcss-gitdiff': { options: { baseUrl:

    'http://localhost:3000/', serverRoot: 'test/files/' }, mobile: { options: { screenshots: 'screens/mobile/', results: 'failures/mobile/', viewportSize: [320, 480] }, src: ['test/files/{,**/}*.html'] ... Gruntfile.js PhantomCSS PhantomJS - scriptable headless browser CasperJS - navigation scripting & caching PhantomCSS - screenshot comparison library npm install grunt-phantomcss-gitdiff Grunt task
  30. 71.

    Warnings Imperfect solution Not as useful on pages with mutable

    content that changes regularly More difficult to use on complex applications Your mileage may vary
  31. 72.

    Evaluate your options and choose the best tool for your

    use-case • Huxley • Wraith • Needle • CSSCritic • dpxdt Many alternatives
  32. 75.

    Just render visible content! 1. One RTT render for above

    the fold 2. Fast server response. No redirects 3. Must optimize critical rendering path a. Inline critical CSS b. Remove any blocking JavaScript Don’t render the whole page!
  33. 76.

    // for each selector in my site.css var elements =

    document.querySelectorAll('.someClass'); // for each element on the page matched for (var i=0; i < elements.length; i++) { // if "above the fold" if (elements[i].getBoundingClientRect().top > window.innerHeight) { // Keep the CSS rules that use this selector keep = true; } } Scripting alone is not good enough https://gist.github.com/PaulKinlan/6284142 Harder to handle.. Special characters - content: '\2192' etc. @-Rules - @font-face, @media, @keyframe pseudo-selectors - :before, :hover
  34. 77.

    Multi-part problem to automate. What do we really need to

    do? 1. Extract stylesheets from HTML ◦ Choice of extraction or defining *.css files upfront 2. Generate the above the fold CSS ◦ Decide on target viewports. Multiple? One sweet spot? ◦ Keep it small and lightweight: under 14 KB 3. Inline critical-path CSS in <head> 4. Asynchronously load the rest of your styles ◦ Remove them from the critical path
  35. 78.

    New Critical-path CSS tools which builds on Penthouse <333 $

    npm install --save-dev penthouse CriticalCSS by FilamentGroup is also solid $ npm install --save-dev criticalcss Critical $ npm install --save-dev critical
  36. 79.

    Extract stylesheets (Oust) Generate Critical path CSS for a viewport

    (Penthouse) Inline styles in <head> (inline-critical) Output Source Critical’s workflow Inject loadCSS & async load site. css Wrap link tags in <noscript> for users with JS disabled
  37. 80.

    function loadCSS( href, before, media ){ var ss = window.document.createElement(

    "link" ); var ref = before || window.document.getElementsByTagName( "script" )[ 0 ]; ss.rel = "stylesheet"; ss.href = href; ss.media = "only x"; // inject link ref.parentNode.insertBefore( ss, ref ); setTimeout( function(){ ss.media = media || "all"; } ); return ss; } Set media back to all so the stylesheet applies once it loads Async load CSS with loadCSS.js Temporarily set media to something non- matching. Fetches without blocking render. loadCSS(‘site.css’) http://filamentgroup.com/lab/performance-rwd.html
  38. 81.
  39. 82.

    critical: { dist: { options: { base: './', css: [

    'app/styles/main.css', 'app/styles/bootstrap.css' ], width: 320, height: 70 }, src: 'app/index.html', dest: 'app/styles/critical.css' } } Specify stylesheets or use Oust to extract them grunt-critical Specify viewport
  40. 84.

    Challenges Background images or Fonts missing Relative paths may need

    updating to absolute Unstyled content showing The most common problem is with clearing floats. Use the clear-fix-pattern. Special glyphs not showing/showing incorrectly When using hexadecimal format in CSS it needs to be prepended with a backslash, like so: \2192
  41. 85.
  42. 87.
  43. 88.

    (1) Optimizations made with best tools available ▪ PNGOUT, Zopfli,

    Pngcrush, AdvPNG, extended OptiPNG, ▪ JpegOptim, jpegrescan, jpegtran, and Gifsicle. (2) Animated GIFs are HARD to automate optimizations to ImageOptim / Imagemin :(
  44. 90.

    (1) Run OSX screencapture every 0.1 seconds ▪ Get a

    folder of images (PNGs) (2) Run `python anim_encoder.py folderName` over the output (3) Single packed PNG with diffs between frames. JS for turning PNG + JSON into animation Packed Image Diffs https://github.com/benvanik/anim_encoder with thanks to @umaar for introducing me to the above workflow (1) Works best for UI where only small areas change between frames (2) ~600KB for our animation. Introduces more render-blocking JS.
  45. 92.
  46. 94.
  47. 100.

    (1) Client renders page, custom JS beacons back ATF CSS

    styles ▪ PageSpeed gathers critical CSS beacons from visitors (2) Critical CSS is inlined... ▪ Remaining CSS loaded after first paint + https://developers.google.com/speed/pagespeed/module/filter-prioritize-critical-css ModPagespeedEnableFilters prioritize_critical_css # Apache pagespeed EnableFilters prioritize_critical_css # Nginx • modpagespeed.com • ngxpagespeed.com
  48. 105.

    WebPageTest CLI $ npm install -g webpagetest Install $ webpagetest

    test <url> $ webpagetest test <url> -- wait 8000 Usage Jenkins
  49. 106.

    Grunt-PerfBudget http://cognition.happycog.com/article/grunt-plugins-reviewed $ npm install grunt-perfbudget Install 1 2 3

    Budget in ms for render, KB for page weight Over budget? Task fails and reports an error. GitHub PRs will show the build failed
  50. 107.

    PageSpeed Insights CLI $ npm install -g psi Install $

    psi <url> -- strategy=mobile Usage
  51. 108.
  52. 109.

    Phantomas CLI $ npm install -g phantomas Install $ phantomas

    --url http://jsconf.eu $ phantomas --url http://jsconf.eu --assert-requests=10 Usage
  53. 113.
  54. 114.

    npm install -g colorguard Install $ colorguard --file styles.css Collision:

    #020202, #000000 - #020202 [line: 2] is too close (0.3146196209793196) to #000000 [line: 2, 3, 7, 12, 13, 16, 17] Collision: #020202, #010101 - #020202 [line: 2] is too close (0.1574963682909058) to #010101 [line: 20] Collision: #000000, #010101 - #000000 [line: 2, 3, 7, 12, 13, 16, 17] is too close (0.15712369811016996) to #010101 [line: 20] Example CSS Colorguard
  55. 115.
  56. 119.
  57. 121.
  58. 122.

    #perfmatters 1. Don’t guess it, test it. ◦ Performance advice

    is addictive. Always measure. 2. Measure, optimize & repeat ◦ Validate your optimizations. Make sure output is ~1:1 3. Set a performance budget ◦ Set goals. Automate performance measurement. 4. Focus on what matters to your users
  59. 128.

    Improving SmashingMag performance http://www.smashingmagazine.com/2014/09/08/improving-smashing-magazine-performance-case-study/ “Strategically speaking, the following could be

    your performance optimization roadmap: • Remove blocking scripts from the header of the page. • Identify and defer non-critical CSS and JavaScript. • Identify critical CSS and load it inline in the head, and then load the full CSS after rendering. • Keep all critical HTML and CSS to under 14 KB, and aim for a Speed Index of under 1000. • Consider using WOFF2 to further reduce latency and file size of the web fonts. • Replace JavaScript libraries with leaner JavaScript modules.”