Performance site internet : Astuces et bonnes pratiques
Certains d’entre vous ont sûrement connu l'époque du 56k. En ce temps là, charger une seule image sur internet pouvait demander plusieurs minutes. Puis est arrivé l’ADSL et le haut débit qui ont démultiplié la vitesse de chargement. Bizarrement j’ai l’impression que nous passons toujours autant de temps à attendre le chargement d’une page web.
De nos jours les sites sont de plus en plus complexes, embarquent de plus en plus de contenu. Grâce à la fibre optique ces derniers se chargent de plus en plus vite… — En théorie — car paradoxalement le web évolue vite, mais les sites web sont toujours aussi long à charger.
Il existe beaucoup d’options pour améliorer la performance de votre site internet. Pour vous aider à décider comment mettre en place ces solutions j’ai découpé cet article en 3 parties :
- Geek
- Hacker
- Guru
Chaque technique peut être déployée partiellement, en partie ou pas du tout. Chaque palier peut vous aider lors du développement de votre site suivant son niveau de complexité.
Geek de la performance
Les 2 choses les plus simples à mettre en place rapidement sont la compression des fichiers et les en-têtes de cache. Ces techniques indispensables vous aiderons à :
- Réduire le poids des pages.
- Réduire le nombre de requêtes http, et donc la latence.
Puisque ces modifications ont lieu côté serveur, elles amélioreront immédiatement les performances de chaque page.
Activer mod_deflate
pour la compression Gzip
de vos fichiers
De la même manière que nous zippons nos pièces jointes envoyées par email, votre serveur peut compresser les fichiers avant de les envoyer au navigateur. Pour préserver la bande passante de vos utilisateurs mobiles, il est capital de réduire le plus possible la taille de votre site.
La librairie de compression pour Apache mod_deflate
fonctionne uniquement sur des fichiers textes comme HTML
, CSS
et JavaScript
. Les images .jpg
, .gif
ou .png
sont compressées à différents niveaux, comme expliqué plus loin dans cet article, cette librairie n’ont donc aucun effet sur elles.
La mise en place demande 3 étapes :
- Aller sur le projet GitHub HTML5Boilerplate.
- Copier le contenu
mod_deflate
du fichier.htaccess
, - et le coller sur votre serveur.
Mettre les ressources en cache
Si votre site est correctement architecturé, les mises à jours des ressources CSS
, JavaScript
et images sont moins fréquentes que le contenu. Dans un contexte mobile nous pouvons télécharger ces ressources statiques en une seule fois, et les mettre en cache sur l’appareil.
- Moins de requêtes http seront effectuées.
- Le contenu total à télécharger est diminué.
De cette façon, pour les futures visites, l’expérience de navigation sera incroyablement plus rapide et donc meilleure. L’astuce consiste à utiliser les entêtes d’expiration avec une date adaptée.
Il n’est pas conseillé de spécifier une durée inférieure à 1 mois et supérieure à un an. Si vous changez régulièrement une ressource vous pouvez :
- Spécifier et identifier cette ressource dans votre fichier
.htaccess
. - Modifier le nom du fichier, qui est une bien meilleure solution car cela donnera naissance à une nouvelle requête http.
La mise en place demande 3 étapes :
- Aller sur le projet GitHub HTML5Boilerplate.
- Copier le fichier
.htaccess
, pour la partiemod_expires
, - et le coller sur votre serveur.
La plus grande limite de cette technique est la taille du cache des appareils mobiles. Un site web simple doit peser en moyenne 2Mo, le cache des appareils Android 2.x est limité à 6Mo, les appareils iOS sont plus avantagés avec un cache de 50Mo.
Pour contourner ce problème nous pouvons mettre en place une fonctionnalité en utilisant l’API HTML5 localStorage
mais pour cela il faut être guru de la performance.
Hacker de la performance
La compression et la mise en cache des fichiers sont de bonnes pratiques mais ce n’est que la base. Pour avoir un réel impact sur la performance et offrir une expérience optimisée à vos utilisateurs vous allez devoir travailler plus. Les techniques de cette partie permettent de :
- Réduire le poids de vos pages.
- Réduire le nombre de requêtes à votre serveur, et donc la latence.
- Afficher du contenu à la demande.
Les techniques de minification et de concaténation devraient êtres mises en places lors de déploiement dans des environnements de test / production. Elles ne sont pas vraiment utiles si vos mises à jours sont fréquentes et multiples.
Mettre vos fichiers au régime.
Minifier votre code source signifie simplement supprimer les octets inutiles d’un fichier (espaces, indentation et saut de ligne). Cette syntaxe est indispensable pour qu’un humain comprenne, mais elle n’est pas nécessaire pour l'éxécution du code sur une machine.
Le code source est écrit pour les humains, pas pour les machines
@drublic
Avec la minification le navigateur télécharge moins de contenu, le rendu de votre page est donc plus rapide.
Si vous utilisez une librairie populaire comme jQuery vous utilisez certainement la version .min
. La minification n’est pas seulement disponible pour le JavaScript, mais peut être appliquée à n’importe quelle type de ressource texte. L'asset
principale qui doit être minifiée dans un code de production est le CSS. La plus vieille solution pour réaliser cette opération est YUI Compressor de yahoo! Si vous êtes un développeur front-end éclairé essayez de chercher du côté des tâches grunt pour automatiser cette opération.
La concaténation : un fichier pour les gouverner tous
Si le père de la performance est la minification, la concaténation des fichiers est sans doute la mère. Par exemple : au lieu de télécharger 10 fichiers JavaScripts qui demandent 10 requêtes http au serveur, les utilisateurs devraient télécharger seulement 4 fichiers qui représentent la combinaison de ces 10 fichiers.
Après les mod_expires
, la concaténation est la meilleure option à mettre en place pour fluidifier la navigation sur mobile. Malheureusement la pratique est plus complexe que la théorie.
En moyenne un navigateur peut télécharger 6 fichiers en parallèle. Comme la minification YUI est un bon outil pour concaténer vos fichiers. Dans un environement ruby c’est l'asset pipeline
qui se charge du boulot, en php c’est quickconcat. Vous pouvez aussi construire votre propre asset pipeline avec gulp
Optimisation des images
Les images sont les éléments qui prennent le plus de place. En moyenne, c’est plus de 60% dans le poids d’une page. C’est à chacun, développeur comme designer, d’optimiser le poids des images. Le processus se fait en plusieurs étapes :
1. Choisir le format adapté
.png
pour les aplats de couleurs, .jpg
pour les photographies. N’enregistrez jamais vos images dans la qualité la plus haute mais essayez de trouver le bon compromis entre qualité / poids.
Avec Photoshop fichier
> enregistrer pour le web
N’oubliez pas de cocher la case jpg progressif, cette technique utilisée pour les débits lents à l'époque du 56k prends tout son sens aujourd’hui dans un contexte de navigation mobile.
2. Supprimer les informations inutiles
Pour gagner quelques octets supplémentaires il est possible de supprimer d’autres informations encapsulées dans les images (métadonnées, informations de claques, …) Cette opération peut se faire très facilement avec des logiciels comme :
- imgOptim pour macOS
- pngGauntlet pour windows
Si vous souhaitez en savoir plus sur l’optimisation des images, je vous invite chaudement à lire les articles de Serguey Chikuyonok’s sur l’optimisation intelligente des images .png
et .jpg
3. Automatiser la tâche
Avec la puissance de node et ImageOptim-CLI il est possible d’automatiser tout ce processus pour vous permettre de gagner un temps considérable.
npm install -g imageoptim-cli
4. Lazy Loading d’images
Comme me l’a fait remarqué @gaelmetais, expert en performance web, la solution qui donne les meilleurs résultats est le lazy loading d’images. Cette solution JavaScript disponible sur github permet de ne charger que les images visible du viewport
. Cela évite de télécharger inutilement des images qui ne sont probablement jamais vues par les visiteurs.
Reporter le chargement du contenu
Toutes les techniques précédentes, ormis la concaténation, vous aiderons à réduire la taille de vos pages. Une autre approche est de prioriser le chargement de votre contenu.
La performance n’augmentera pas, c’est le sentiment de vitesse que ressentira l’utilisateur qui doit être perceptible. Le moyen le plus simple de retarder le chargement d’un fichier JavaScript en utilisant l’attribut HTML5 defer
ou async
.
<script defer src="application.js"></script>
<script async src="application.js"></script>
D’un point de vue latence et performance ces attributs se comportent de façon similaire. Ils demandent au navigateur d'éxécuter les scripts seulement après avoir téléchargé l’intégralité du contenu de la page.
Vous devez vous poser la question : quel priorité dois-je utiliser ?
defer
charge les scripts dans l’ordre d’appel
Supposons que vous chargez la librairie jQuery ainsi qu’un autre fichier de plug-in. Ces 2 fichiers sont dépendant car le second script doit être chargé après le premier.
async
le chargement de l’ordre des fichiers n’a aucune importance
Guru de la performance
Les geeks et les hackers de la performance utilisent des techniques d’optimisation traditionnelles pour la construction de sites internet, bien avant l’apparition du responsive design.
Les techniques de guru peuvent êtres mises en place pour des applications web HTML5 avec un focus pour les navigateurs mobiles. Elles permettent de :
- Réduire le poids de vos pages.
- Réduire le nombre de requêtes http, et donc la latence.
- Optimiser le chargement du contenu pour être utilisé plus rapidement.
Dans certains cas il ne sera pas possible de garantir le résultat sur de vieux navigateurs. N’hésitez pas à vérifier les différentes fonctionnalités sur le site caniuse.
Ordre des sources
Curieusement organiser correctement votre CSS et vos fichiers JavaScript peut avoir un large impact sur le ressenti de la rapidité de chargement.
JavaScript bloque le chargement de votre contenu
Voici un très mauvais exemple que je rencontre quotidiennement :
<head>
<script src="jquery.js"></script>
<link rel="stylesheet" href="small.css">
<link rel="stylesheet" href="big.css">
</head>
Vous ne devez JAMAIS faire cela. Le JavaScript bloque téléchargement des autres ressources en parallèle comme les images. Sauf exception votre JavaScript doit toujours être appelé uniquement avant la fin du </body>
localStorage
comme cache navigateur
localStorage
est une spécification du W3C. Cette technologie est comparable aux cookies utilisés par les développeurs pour stocker des informations de type clef / valeur. Elles sont sauvegardées même si le navigateur est fermé. Contrairement aux cookies les informations associées au localStorage
ne sont jamais renvoyées au serveur depuis le client.
Voici un exemple assez basique : utiliser localStorage
pour mettre en cache jQuery
<-- Script tag that will hold jQuery -->
<script id="js-jquery"></script>
<-- Determine if jQuery should be loaded from localStorage or the server -->
<script>
var jqFile;
if ('jqFile' in window.localStorage) {
// 1. The script is already stored
jqFile = window.localStorage.getItem('jqFile');
} else {
// 2. not present, AJAX request to get the data
jqFile = getJQFile();
// push the data into localStorage
window.localStorage.setItem('jqFile',jqFile);
}
// 3. Insert JavaScript into the script element
document.getElementById('js-jquery').text = jqFile;
</script>
- Vérifier si le fichier existe
- Charger le contenu en AJAX
- Insérer le contenu dans la page avec
js-jquery
Il faut noter que localStorage
ne fonctionne qu’avec des string
. Si vous souhaiter utiliser cette méthode pour stocker des images, vous devez les parser en base64 d’abord.
localStorage
est une solution assez facile à mettre en place pour des choses basiques. Si vous souhaitez aller plus loin je vous conseille d’essayer basket.js maintenu par Addy Osmani qui permet de prioriser le chargement du JavaScript en cache.
Lazy loading JavaScript
Si votre application web / site internet embarque beaucoups de JavaScript il peut être intéressant de d’utiliser des techniques de lazy loading pour réduire le temps de démarrage.
Quand un navigateur télécharge du JavaScript, il le parcours et l’exécute. Comme expliqué précédemment, cela bloque le rendu de la page jusqu'à ce que le processus soit terminé. Dans la plupart des cas, vous n’avez sûrement pas besoin que tout votre JavaScript soit parcouru et exécuté au chargement de la page. Cela porte préjudice à la performance sans raison valable.
Il existe 2 techniques pour corriger le problème :
- Modifier le script précédemment utilisé pour
localStorage
en utilisant JavaScript pour insérer du JavaScript. - Utiliser
XmlHttpRequest
pour télécharger et évaluer le code. Le principal problème est que si l’utilisateur essaye d’utiliser une fonctionnalité qui n’est pas encore téléchargé cela risque de "casser" la mise en page.
L'équipe qui s’occupe de Gmail a trouvé une solution pour que le code ne soit pas exécuté : commenter le code.
Le navigateur télécharge et évalue l’intégralité de votre JavaScript, mais comme ce dernier est commenté, il n’est pas exécuté. Cette méthode libère du CPU pour effectuer d’autres opérations. Quand l’utilisateur a besoin d’une fonctionnalité, une partie du code est décommentée et évaluée. Voici un exemple :
<html>
…
<script id="js-module-lazy">
/*
JavaScript commented code
*/
</script>
<script>
function lazyLoad(){
var lazyElement = document.getElementById('js-module-lazy');
var lazyElementContent = lazyElement.innerHTML;
var jsCode = stripOutCommentBlock(lazyElementContent);
eval(jsCode);
}
</script>
<button onclick="lazyLoad()">Lazy load feature</button>
</html>
Cette technique est complexe à mettre en place car votre architecture JavaScript doit être irréprochable.
Le cas des boutons sociaux
Fin 2011, le magazine Allemand Heise a publié un nouvel ensemble d’icônes pour les réseau sociaux très connu. La différence ? Il faut 2 clics pour “aimer”, “tweeter” ou ajouter “+1”.
De base les images des icones sont chargées. Si l’utilisateur souhaite partager, alors les widgets de partage sont téléchargés. Cette solution présente de nombreux avantages non négligeables.
- Les utilisateurs ne sont pas constamment trackés. Les widgets ne sont activés que si l’utilisateur le demande et non par défaut.
- Extrèmement efficace avec du responsive design.
Pourquoi les boutons sociaux tuent votre site web ?
De plus vous ne téléchargez que ce qui est nécessaire. Si un utilisateur n’est actif que sur twitter, l’obliger à télécharger le widget facebook n’a pas de sens, et cela lui évite un temps de latence en supprimant les requêtes http inutiles.
Utiliser des sprites pour concaténer vos images
Les fichiers CSS et JavaScript ne sont pas les seuls à pouvoir êtres combinés pour réduire le nombre de requêtes. Utilisés généralement pour des icones ou de petites illustrations, la technique des sprites CSS est une bonne solution.
Essayez de regrouper des images partageant la même palette de couleur. Si ce n’est pas le cas la taille de votre fichier sera anormalement élevée car il sera sauvegardé au format PNG true color
au lieu du classique PNG 256 couleurs. Pour éviter une requête avec des images de petite taille, vous pouvez aussi encoder le résultat obtenu en base64 pour optimiser encore plus la taille de votre fichier (à prendre avec précaution car cela peut augementer la taille jusqu'à 37%).
Éviter le calcul navigateur aka browser reflow
Une fonctionnalité peu connue des développeurs en terme de performance est la construction d’une page web dans une fenêtre de navigateur. Des problèmes de performance apparaissent dès que l’on essaye de trop modifier dynamiquement la mise en page. Cela force le navigateur à recalculer la place des objets tout en chargeant la page, ce qui ralenti le rendu de la page.
La chose la plus importante pour limiter le nombre de "reflow" est de limiter la taille du DOM et le nombre de sélecteurs CSS le plus possible. Moins le DOM contient d'éléments, moins d’objets doivent êtres calculés et positionnés pendant la construction de la page et plus elle se chargera vite. Je ne le répéterai jamais assez :
JavaScript est pour le comportement, CSS pour le style.
C’est pourquoi vous ne devez JAMAIS modifier vos éléments avec du JavaScript.
var el = document.getElementById('js-box');
el.style.color = "#fff";
el.style.backgroundColor = "#000";
el.style.borderColor = "#fc0";
Chaque déclaration provoque un calcul. Dans notre cas il y a 3 reflow.
var el = document.getElementById('js-box');
el.className = "m-box";
1 seul reflow. Le style est déclaré à sa place : dans une feuille de style et vous n’aurez pas besoin d’utiliser !important
si votre élément change.
Les calculs sont aussi impactés par l’ajout d'élements au DOM.
Il y a le bon :hover et le mauvais :hover
Pour aller plus loin et comprendre le fonctionnement d’un navigateur web je vous invite à regarder l’excellente présentation de Paul Rouget développeur chez Mozilla. Ou encore le projet css-reflow-tracer.
Sur mobile toucher est meilleur que cliquer
L’impression de rapidité et la performance sont 2 choses différentes.
Connaissez-vous le célèbre délai des 300ms implémenté par tous les appareils mobiles ? Ce délai permet aux utilisateurs d’avoir le temps d’effectuer un double-tap. Dans certains cas il n’est pas nécessaire et pour retirer ce délai il existe des solutions :
- Comment créer des boutons rapides ?
- Le polyfill Fastclic.js
Aller à l’essentiel et supprimer les énormes frameworks
JavaScript n’est pas le seul responsable dans l’explosion du poids des pages web, notamment depuis que l’internet se bootstrapize. Le framework bootsrap de twitter est une excellente solution mais utilisez ses composants avec partimonie. Préférez lui une solution plus légère comme Foundation ou encore KNACSS. Vous pouvez aussi envisager de construire votre propre grille avec Suzy et créer vos propres composants.
Il est facile d’inclure dans votre projet des librairies comme jQuery ou mootools, et d’y ajouter une myriade de plugins. En tant que développeurs nous devons nous poser la question de ce qui est vraiment utile. Si vous utiliser jQuery seulement comme outil de sélection $('element')
regardez du coté de Zest ou qwery. Ces micro framework JavaScript sont spécialement crées pour ça et leur taille est d’environ 11ko comparé à plus de 90ko.
Comme expliqué précédemment, quand un navigateur télécharge jQuery, il doit parcourir le fichier. Cela demande du temps et bloque le rendu de la page. Soyez critique quand vous analysez vos besoins en JavaScript. 11ko c’est peut-être 11ko de trop si la seule chose dont vous avez besoin est document.getElementByTagName('foo')
.
La performance comme budget
Généralement la performance ne fait pas l’objet d’un budget pour un projet web. Mais tout comme les créateurs de jeux vidéos qui ont une limite dans le nombre de polygones affichés à l'écran, les développeurs devraient imposer une limite de taille pour alléger le poids des sites internets.
Si votre client est résistant à se soucier de la performance, voici une petite astuce qui fonctionne :
- Sélectionner deux sites (au hasard le site web du client ainsi qu’un concurrent)
- préchargez / precachez le site du concurrent en dur dans le cache (avec
localStorage
) - et l’exécuter en comparant le site internet du client non mise en cache.
Personne ne veut attendre et les gens sont impatient, à partir du moment où le client comprendra la différence, il voudra un site web rapide, et investira pour avoir une bonne performance.
C’est culotté, mais cette méthode permet de démontrer l’importance de la performance. Je ne pense pas que cette façon de faire soit différente des publicicités télévisées que l’on voit à longeur de journée.
Pour aller plus loin, vous pouver créez un graphique comparatif du temps de chargement contre le trafic en temps réel, le client verra la corrélation entre les deux. De nombreuses décisions devront être réexaminées dans le but d’une meilleure performance, je crois que c’est une très, très bonne chose !
Ce n’est pas fini
Ai-je manqué quelque chose? Le contenu n'est plus à jour? Contactez @flexbox_
Je met continuellement à jour ces guides afin d’avoir un contenu le plus précis et le plus à jour sur le Web.
Performance site internet : Astuces et bonnes pratiques
Tweet