Slide 1

Slide 1 text

@addyosmani +AddyOsmani CSS PERFORMANCE TOOLING

Slide 2

Slide 2 text

When you want to be fast, you have to give up the things slowing you down.

Slide 3

Slide 3 text

Optimising Performance.

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

Waiting for my page to render. Why care about optimization tooling?

Slide 6

Slide 6 text

300-1000ms 1 second + 10 seconds + Later. 0-100ms Human Perception in 2014

Slide 7

Slide 7 text

Case Study Assume cable speeds used for testing unless otherwise noted.

Slide 8

Slide 8 text

Optimizing JSConf.eu

Slide 9

Slide 9 text

JSConf.eu Friday 3G

Slide 10

Slide 10 text

JSConf.eu Friday Cable

Slide 11

Slide 11 text

JSConf.eu Monday Cable

Slide 12

Slide 12 text

Make JSConf.eu an instant experience.

Slide 13

Slide 13 text

Make your site an instant experience.

Slide 14

Slide 14 text

Step 1: Measure

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Lower score is always better SI Visualized

Slide 17

Slide 17 text

~1s page load Max 200ms server response time Speed Index under 1000 Performance Budget

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Monday Mobile 3G (Fast) Cable

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Friday Ideally 85 Mobile 90 Desktop

Slide 22

Slide 22 text

Monday Regression

Slide 23

Slide 23 text

https://www.flickr.com/photos/tamakisono/668326457

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

https://www.flickr.com/photos/mipsyretro/5593568015 #ILoveRoamingCharges

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Profiling Tools Are Now Everywhere!

Slide 29

Slide 29 text

Accidental slowness is a problem many of us face.

Slide 30

Slide 30 text

soup.io The web

Slide 31

Slide 31 text

HTTPArchive - August 2014 Average page size 1.8MB ~1.2MB images ~0.3MB scripts & styles

Slide 32

Slide 32 text

http://perf.fail/ Perf.fail

Slide 33

Slide 33 text

Step 2: Optimise

Slide 34

Slide 34 text

It’s basically Tinder for Node modules

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Party like it’s 1977.

Slide 37

Slide 37 text

Build Tools Make Had no logo so it gets a platypus

Slide 38

Slide 38 text

Minify CSS, HTML, JS & Images

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Minify duplicates, colors, keyframes, pseudos, filters, font-weight

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

CSS, JS, HTML, Image minification New Speed Index 1321 Old Speed Index 2093

Slide 46

Slide 46 text

Remove unused CSS

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

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?

Slide 49

Slide 49 text

Isn’t using 56% of the site wide styles being shipped Page A

Slide 50

Slide 50 text

Isn’t using ~56% of them Page B

Slide 51

Slide 51 text

Isn’t using ~59% Page C

Slide 52

Slide 52 text

Pattern? Maybe. Optimize, then check mileage.

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

UnCSS as a post-processor HTML, JavaScript Sass Minified HTML CSS UnCSS Minify Done Source Minified JavaScript Works with Sass, Less, Stylus

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

Unused CSS removed Speed Index 1316 Old Speed Index 2093

Slide 63

Slide 63 text

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.

Slide 64

Slide 64 text

CSS Regression Testing Useful for more than just catching imperfect updates

Slide 65

Slide 65 text

Build-time styles & UI verification Before After Diff

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

Verifies visual optimizations didn’t mess up.

Slide 70

Slide 70 text

0.06% difference from the original

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

Evaluate your options and choose the best tool for your use-case ● Huxley ● Wraith ● Needle ● CSSCritic ● dpxdt Many alternatives

Slide 73

Slide 73 text

Optimize Critical Path CSS

Slide 74

Slide 74 text

Our goal is to show content asap

Slide 75

Slide 75 text

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!

Slide 76

Slide 76 text

// 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

Slide 77

Slide 77 text

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 4. Asynchronously load the rest of your styles ○ Remove them from the critical path

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

Extract stylesheets (Oust) Generate Critical path CSS for a viewport (Penthouse) Inline styles in (inline-critical) Output Source Critical’s workflow Inject loadCSS & async load site. css Wrap link tags in for users with JS disabled

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

Critical-path CSS optimized version New Speed Index 1225 Old Speed Index 2093

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

Bottleneck: that 5MB GIF...

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

(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 :(

Slide 89

Slide 89 text

GIFBrewery ~1MB half-res, 256 colors ~4MB full-res, 256 colors

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

~450KB

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

Minify + UnCSS + New Speed Index 1327 Old Speed Index 2093

Slide 94

Slide 94 text

static?

Slide 95

Slide 95 text

Minify + UnCSS + static header Speed Index 923 Old Speed Index 2093

Slide 96

Slide 96 text

grunt-critical + optimisations + static header Speed Index 917 Old Speed Index 2093

Slide 97

Slide 97 text

What’s important to you?

Slide 98

Slide 98 text

Automating Tier 1 + Tier 2

Slide 99

Slide 99 text

A magic bullet? No, Timmy

Slide 100

Slide 100 text

(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

Slide 101

Slide 101 text

Tuesday: JSConf.eu New images Old Speed Index 2149

Slide 102

Slide 102 text

Optimized: JSConf.eu + mod_pagespeed Old Speed Index 2149 New Speed Index 1310

Slide 103

Slide 103 text

Mileage does vary (a few changes later..) Old Speed Index 1310 New Speed Index 1542

Slide 104

Slide 104 text

Automate performance measurement Detect when you’ve fallen off the fast-path

Slide 105

Slide 105 text

WebPageTest CLI $ npm install -g webpagetest Install $ webpagetest test $ webpagetest test -- wait 8000 Usage Jenkins

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

PageSpeed Insights CLI $ npm install -g psi Install $ psi -- strategy=mobile Usage

Slide 108

Slide 108 text

Grunt-PageSpeed $ npm install grunt-pagespeed $ grunt pagespeed Usage Install Set performance thresholds for mobile/desktop!

Slide 109

Slide 109 text

Phantomas CLI $ npm install -g phantomas Install $ phantomas --url http://jsconf.eu $ phantomas --url http://jsconf.eu --assert-requests=10 Usage

Slide 110

Slide 110 text

Grunt-Phantomas $ npm install grunt-phantomas Install $ grunt phantomas:default $ grunt phantomas:screenshot Usage

Slide 111

Slide 111 text

Tier 3: Stylesheet Complexity Analysis

Slide 112

Slide 112 text

The easiest way to keep CSS maintainable is to minimize repetition.

Slide 113

Slide 113 text

No content

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

http://www.stylestats.org

Slide 117

Slide 117 text

http://www.wallarc.com/wallpaper/view/370816 Step 3: Rinse & Repeat

Slide 118

Slide 118 text

about:blank is the baseline to beat

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

Stay light, stay fast.

Slide 121

Slide 121 text

1.1 seconds 12.1 seconds ~ 2100 1321 1316 1225 1327 923 917 Speed Index Scores

Slide 122

Slide 122 text

#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

Slide 123

Slide 123 text

https://www.flickr.com/photos/keijoknutas/8850877937

Slide 124

Slide 124 text

We have one last thing to do. A pull request.

Slide 125

Slide 125 text

CSSConf LGTM’d!

Slide 126

Slide 126 text

Let’s Perf The Web Forward Together <3

Slide 127

Slide 127 text

High-Performance Browser Networking Udacity Perf Optimization https://www.udacity.com/course/ud884

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

Getting Your PageSpeed Score Up https://www.youtube.com/watch?v=pNKnhBIVj4w

Slide 130

Slide 130 text

#perfmatters +AddyOsmani @addyosmani