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

Les performances Web: Soyez responsable!

Les performances Web: Soyez responsable!

Jamais les connections internet n’auront été aussi rapides. Pourtant la perception est que le web est de plus en plus lent. Un usager exige qu’une page web soit disponible le plus vite possible, souvent sous les 2 secondes. Les 100 sites les plus consultés au monde ne sont même pas proche de cette limite psychologique.

Il n’y a rien de plus frustrant que d’attendre. Il devient donc impératif d’avoir un site web qui s’affiche rapidement, peu importe le type d’appareil utilisé. Surtout dernièrement, la navigation mobile a surpassé celle de l’ordinateur de bureau. La vitesse de chargement devient donc une fonctionnalité importante pour accrocher et conserver les usagers qui fréquentent votre site.

Durant cette conférence, nous démystifierons l’optimisation du temps de chargement d’une page web à l’aide de quelques techniques et outils, que vous pourrez facilement intégrer à votre méthodologie de développement.

Pierre-Luc Babin

March 18, 2015
Tweet

More Decks by Pierre-Luc Babin

Other Decks in Programming

Transcript

  1. Un budget de performance est une limite imposée sur certaines

    métriques, pour chaque page de votre site.
  2. https://github.com/tkadlec/grunt-perfbudget perfbudget: { default: { options: { url: ‘http://pinkman-biatch.com', key:

    'WEBPAGETEST_API_KEY', runs: 5, budget: { requests: '40', SpeedIndex: ‘1000’, bytesIn: ‘400’ } } } }
  3. CSS dans le head <!DOCTYPE html> <html> <head> <link href="yeah/bitch.12947498.css"

    rel="stylesheet"> <title>Jesse Pinkman Official Fan Page</title> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> </head> <body> ... </body> </html>
  4. <!DOCTYPE html> <html> <head> <link href="yeah/bitch.12947498.css" rel="stylesheet"> <title>Jesse Pinkman Official

    Fan Page</title> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> </head> <body> ... </body> </html> CSS dans le head
  5. Javascript à la fin du body <!DOCTYPE html> <html> <head>

    <link href="yeah/bitch.12947498.css" rel="stylesheet"> <title>Jesse Pinkman Official Fan Page</title> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> </head> <body> ... <script type='text/javascript' src='yeah.bitch.magnets!.13875.js'></script> </body> </html>
  6. Javascript à la fin du body <!DOCTYPE html> <html> <head>

    <link href="yeah/bitch.12947498.css" rel="stylesheet"> <title>Jesse Pinkman Official Fan Page</title> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> </head> <body> ... <script type='text/javascript' src='yeah.bitch.magnets!.13875.js'></script> </body> </html>
  7. @charset "UTF-8";.text-center{text-align:center}.text-left{text- align:left}.text-right{text-align:right}.pull- left{float:left}.pull- right{float:right}.clearfix:before,.clearfix:after{display:table; content:" "}.clearfix:after{clear:both}.hidden{display:none}.header- controls .header-controls__dropdown a:after,.media-object--

    folder:before,.media-object--usb:before,.menubarIcon-- volume:before,.menubarIcon--volumeHigh:before,.menubarIcon-- volumeLow:before,.media-object--photo:before,.icon-- refresh:before,.menubarIcon--search:before,.sp- search__form:before,li.header- controls__search:after,.menubarIcon--settings:before,.icon-- fav:before,.media-object--video:before,.menubarIcon-- volumeNone:before,.menubarIcon--wifi:before,.menubarIcon-- wifi__networks:after,.icon--compose:before,.musicControl-- next:before,.media-object--file:before,.header-controls__button-- grid:before,.menubarIcon--battery:before,.musicControl-- pause:before,.header-controls__button-- share:before,.widget__messages:before,.musicControl-- prev:before,.header-controls__button-- list:before,.calendar__nav--left:before,.calendar__nav-- right:before{font-style:normal;font-weight:400;text- decoration:none;text-rendering:optimizeLegibility;white- space:nowrap;-ms-font-feature-settings:"liga" 1;-webkit-font- feature-settings:"liga";font-feature-settings:"liga";-webkit- font-smoothing:antialiased}html:hover .header-controls .header- controls__dropdown a:after,.header-controls .header- controls__dropdown html:hover a:after,html:hover .media-object-- folder:before,html:hover .media-object-- usb:before,html:hover .menubarIcon-- volume:before,html:hover .menubarIcon-- volumeHigh:before,html:hover .menubarIcon-- volumeLow:before,html:hover .media-object-- photo:before,html:hover .icon-- refresh:before,html:hover .menubarIcon-- search:before,html:hover .sp-search__form:before,html:hover li.header-controls__search:after,html:hover .menubarIcon-- settings:before,html:hover .icon--fav:before,html:hover .media- object--video:before,html:hover .menubarIcon-- volumeNone:before,html:hover .menubarIcon--wifi:before,html:hover .menubarIcon--wifi__networks:after,html:hover .icon-- compose:before,html:hover .musicControl-- next:before,html:hover .media-object-- file:before,html:hover .header-controls__button-- grid:before,html:hover .menubarIcon-- minification // Icon Listings // -------------------------------------------------- .applications__listing { margin: 0 -10px; // account for icon margins padding: 0; } .applications__icon { // Width and height need padding added around. width: ($application-icon + 20); position: relative; display: block; margin: 10px 10px 0; float: left; text-transform: uppercase; text-align: center; } .applications__icon a { display: block; line-height: 20px; font-size: 11px; color: #fff; padding-top:$application-icon + 20px; position: relative; &:before{ background-color: rgba($action-active, 0); height: ($application-icon + 20); position:absolute; content:''; width:100%; top:0; left:0; border-radius: 3px; } &:hover:before { transition: .075s all linear; background-color: rgba($action-active, .5); } }
  8. grunt-spritesmith en action .icon-sylvain_carle-227x190-150x150 { background-image: url(sprite_avatar.jpg); background-position: -420px -126px;

    width: 42px; height: 42px; } .icon-waq-david-eaves-150x150 { background-image: url(sprite_avatar.jpg); background-position: -42px -252px; width: 42px; height: 42px; } .icon-waq-hilary-mason-150x150 { background-image: url(sprite_avatar.jpg); background-position: -84px -252px; width: 42px; height: 42px; } .icon-waq-jean-marc-dejonghe-150x150 { background-image: url(sprite_avatar.jpg); background-position: -252px -84px; width: 42px; height: 42px; }
  9. configuration nginx # cache.appcache, your document html and data location

    ~* \.(?:manifest|appcache|html?|xml|json)$ { expires -1; access_log logs/static.log; } # Feed location ~* \.(?:rss|atom)$ { expires 1h; add_header Cache-Control "public"; } # Media: images, icons, video, audio, HTC location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { expires 1M; access_log off; add_header Cache-Control "public"; } # CSS and Javascript location ~* \.(?:css|js)$ { expires 1y; access_log off; add_header Cache-Control "public"; }
  10. configuration apache # CSS ExpiresByType text/css "access plus 1 year"

    # Data interchange ExpiresByType application/json "access plus 0 seconds" ExpiresByType application/ld+json "access plus 0 seconds" ExpiresByType application/schema+json "access plus 0 seconds" ExpiresByType application/vnd.geo+json "access plus 0 seconds" ExpiresByType application/xml "access plus 0 seconds" ExpiresByType text/xml "access plus 0 seconds" # Favicon (cannot be renamed!) and cursor images ExpiresByType image/vnd.microsoft.icon "access plus 1 week" ExpiresByType image/x-icon "access plus 1 week" # JavaScript ExpiresByType application/javascript "access plus 1 year" ExpiresByType application/x-javascript "access plus 1 year" ExpiresByType text/javascript "access plus 1 year" # Media files ExpiresByType audio/ogg "access plus 1 month" ExpiresByType image/bmp "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType image/webp "access plus 1 month" ExpiresByType video/mp4 "access plus 1 month" ExpiresByType video/ogg "access plus 1 month" ExpiresByType video/webm "access plus 1 month"
  11. Créer le css critique // ==================================== // IMPORTS - CRITICAL

    CSS // ==================================== @import "reset.css" @import "partials/mixins" @import "partials/variables" @import "partials/base" @import "partials/typography" @import "partials/icons" @import "partials/layout" @import "partials/navigation"
  12. Injecter le CSS critique <!DOCTYPE html> <html> <head> <meta name="css-all"

    content="yeah/bitch.12947498.css"> <style> /* CSS Critique */ button,html,input,select,textarea{color:#000;} ...; </style> <script> // inline load.css (function( window, undefined ) { function getMeta( metaname ){ ... }; function cookie( name, value, days ){ ... } function loadCSS( href, before, media, callback ){ ... } var cssfile = getMeta('css-all'); if( cssfile && !cookie( cssfile ) ){ loadCSS( cssfile ); cookie( cssfile, "true", 7 ); // pour la cache côté serveur } }( this )); </script> <noscript> <link href="yeah/bitch.12947498.css" rel="stylesheet"> </noscript> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  13. CSS critique dans le head <!DOCTYPE html> <html> <head> <meta

    name="css-all" content="yeah/bitch.12947498.css"> <style> /* CSS Critique */ button,html,input,select,textarea{color:#000;} ...; </style> <script> // inline load.css (function( window, undefined ) { function getMeta( metaname ){ ... }; function cookie( name, value, days ){ ... } function loadCSS( href, before, media, callback ){ ... } var cssfile = getMeta('css-all'); if( cssfile && !cookie( cssfile ) ){ loadCSS( cssfile ); cookie( cssfile, "true", 7 ); // pour la cache côté serveur } }( this )); </script> <noscript> <link href="yeah/bitch.12947498.css" rel="stylesheet"> </noscript> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  14. Meta dans le head <!DOCTYPE html> <html> <head> <meta name="css-all"

    content="yeah/bitch.12947498.css"> <style> /* CSS Critique */ button,html,input,select,textarea{color:#000;} ...; </style> <script> // inline load.css (function( window, undefined ) { function getMeta( metaname ){ ... }; function cookie( name, value, days ){ ... } function loadCSS( href, before, media, callback ){ ... } var cssfile = getMeta('css-all'); if( cssfile && !cookie( cssfile ) ){ loadCSS( cssfile ); cookie( cssfile, "true", 7 ); // pour la cache côté serveur } }( this )); </script> <noscript> <link href="yeah/bitch.12947498.css" rel="stylesheet"> </noscript> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  15. Fonctions pour télécharger le css <!DOCTYPE html> <html> <head> <meta

    name="css-all" content="yeah/bitch.12947498.css"> <style> /* CSS Critique */ button,html,input,select,textarea{color:#000;} ...; </style> <script> // inline load.css (function( window, undefined ) { function getMeta( metaname ){ ... }; function cookie( name, value, days ){ ... } function loadCSS( href, before, media, callback ){ ... } var cssfile = getMeta('css-all'); if( cssfile && !cookie( cssfile ) ){ loadCSS( cssfile ); cookie( cssfile, "true", 7 ); // pour la cache côté serveur } }( this )); </script> <noscript> <link href="yeah/bitch.12947498.css" rel="stylesheet"> </noscript> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  16. Télécharge le CSS principal <!DOCTYPE html> <html> <head> <meta name="css-all"

    content="yeah/bitch.12947498.css"> <style> /* CSS Critique */ button,html,input,select,textarea{color:#000;} ...; </style> <script> // inline load.css (function( window, undefined ) { function getMeta( metaname ){ ... }; function cookie( name, value, days ){ ... } function loadCSS( href, before, media, callback ){ ... } var cssfile = getMeta('css-all'); if( cssfile && !cookie( cssfile ) ){ loadCSS( cssfile ); cookie( cssfile, "true", 7 ); // pour la cache côté serveur } }( this )); </script> <noscript> <link href="yeah/bitch.12947498.css" rel="stylesheet"> </noscript> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  17. Noscript <!DOCTYPE html> <html> <head> <meta name="css-all" content="yeah/bitch.12947498.css"> <style> /*

    CSS Critique */ button,html,input,select,textarea{color:#000;} ...; </style> <script> // inline load.css (function( window, undefined ) { function getMeta( metaname ){ ... }; function cookie( name, value, days ){ ... } function loadCSS( href, before, media, callback ){ ... } var cssfile = getMeta('css-all'); if( cssfile && !cookie( cssfile ) ){ loadCSS( cssfile ); cookie( cssfile, "true", 7 ); // pour la cache côté serveur } }( this )); </script> <noscript> <link href="yeah/bitch.12947498.css" rel="stylesheet"> </noscript> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  18. Optimiser l’injection de @font-face @font-face { font-family: 'Proxima Nova'; src:

    url('/css/fonts/proximanova-light-webfont.woff2') format('woff2'), url('/css/fonts/proximanova-light-webfont.woff') format('woff'), url('/css/fonts/proximanova-light-webfont.ttf') format('truetype'); font-weight: 300; font-style: normal; } body { font-family: Arial, sans-serif; } .proxima-loaded body { font-family: Proxima Nova, Arial, sans-serif; }
  19. Optimiser l’injection de @font-face @font-face { font-family: 'Proxima Nova'; src:

    url('/css/fonts/proximanova-light-webfont.woff2') format('woff2'), url('/css/fonts/proximanova-light-webfont.woff') format('woff'), url('/css/fonts/proximanova-light-webfont.ttf') format('truetype'); font-weight: 300; font-style: normal; } body { font-family: Arial, sans-serif; } .proxima-loaded body { font-family: Proxima Nova, Arial, sans-serif; }
  20. Optimiser l’injection de @font-face @font-face { font-family: 'Proxima Nova'; src:

    url('/css/fonts/proximanova-light-webfont.woff2') format('woff2'), url('/css/fonts/proximanova-light-webfont.woff') format('woff'), url('/css/fonts/proximanova-light-webfont.ttf') format('truetype'); font-weight: 300; font-style: normal; } body { font-family: Arial, sans-serif; } .proxima-loaded body { font-family: Proxima Nova, Arial, sans-serif; }
  21. Optimiser l’injection de @font-face @font-face { font-family: 'Proxima Nova'; src:

    url('/css/fonts/proximanova-light-webfont.woff2') format('woff2'), url('/css/fonts/proximanova-light-webfont.woff') format('woff'), url('/css/fonts/proximanova-light-webfont.ttf') format('truetype'); font-weight: 300; font-style: normal; } body { font-family: Arial, sans-serif; } .proxima-loaded body { font-family: Proxima Nova, Arial, sans-serif; }
  22. Optimiser l’injection de @font-face <!DOCTYPE html> <html> <head> <link rel="stylesheet"

    href="yeah/bitch.12947498.css"> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... <script> /* inline le polyfil https://github.com/bramstein/fontfaceobserver/ */ (function( w ){ if( w.document.documentElement.className.indexOf( "proxima-loaded" ) > -1 ) return; var fontA = new w.FontFaceObserver( "Proxima Nova", { weight: 300 }); var fontB = new w.FontFaceObserver( "Proxima Nova", { weight: 600 }); w.Promise.all( [fontA.check(), fontB.check()] ).then(function(){ w.document.documentElement.className += " proxima-loaded"; cookie( "proxima-loaded", "true", 7 ); }); }( this )); </script> </body> </html>
  23. Optimiser l’injection de @font-face <!DOCTYPE html> <html> <head> <link rel="stylesheet"

    href="yeah/bitch.12947498.css"> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... <script> /* inline le polyfil https://github.com/bramstein/fontfaceobserver/ */ (function( w ){ if( w.document.documentElement.className.indexOf( "proxima-loaded" ) > -1 ) return; var fontA = new w.FontFaceObserver( "Proxima Nova", { weight: 300 }); var fontB = new w.FontFaceObserver( "Proxima Nova", { weight: 600 }); w.Promise.all( [fontA.check(), fontB.check()] ).then(function(){ w.document.documentElement.className += " proxima-loaded"; cookie( "proxima-loaded", "true", 7 ); }); }( this )); </script> </body> </html>
  24. Optimiser l’injection de @font-face <!DOCTYPE html> <html> <head> <link rel="stylesheet"

    href="yeah/bitch.12947498.css"> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... <script> /* inline le polyfil https://github.com/bramstein/fontfaceobserver/ */ (function( w ){ if( w.document.documentElement.className.indexOf( "proxima-loaded" ) > -1 ) return; var fontA = new w.FontFaceObserver( "Proxima Nova", { weight: 300 }); var fontB = new w.FontFaceObserver( "Proxima Nova", { weight: 600 }); w.Promise.all( [fontA.check(), fontB.check()] ).then(function(){ w.document.documentElement.className += " proxima-loaded"; cookie( "proxima-loaded", "true", 7 ); }); }( this )); </script> </body> </html>
  25. Optimiser l’injection de @font-face <!DOCTYPE html> <html class="proxima-loaded"> <head> <link

    rel="stylesheet" href="yeah/bitch.12947498.css"> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>
  26. Optimiser l’injection de @font-face <!DOCTYPE html> <html class="proxima-loaded"> <head> <link

    rel="stylesheet" href="yeah/bitch.12947498.css"> <title>Jesse Pinkman Official Fan Page</title> </head> <body> ... </body> </html>