Chapitre 420 minDébutant
Écoconception web : poids des pages, images et cache
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- mesurer le poids, les requêtes et la taille du DOM d'une page ;
- supprimer les fonctionnalités inutiles avant d'optimiser ;
- choisir le format, la taille et le chargement de chaque image ;
- alléger polices, CSS, JavaScript et services tiers ;
- configurer le cache HTTP et la compression sur Apache.
5 exercices corrigés1 schéma
Écoconcevoir un site web, c'est réduire ce qu'une page fait télécharger, calculer et afficher, sans rien retirer de ce qui est utile à l'utilisateur. Une page légère charge plus vite, coûte moins cher à héberger, reste utilisable sur un vieux téléphone et une connexion lente, et ne pousse personne à changer d'appareil. Ce chapitre suit l'optimisation d'une vraie page, du diagnostic au résultat : besoin, images, polices, JavaScript, services tiers, cache et compression.
Ce que pèse une page web
Quand tu ouvres une page, le navigateur télécharge d'abord le HTML, puis chaque ressource qu'il référence : feuilles de style, scripts, polices, images, vidéos, contenus de services tiers. Chaque ressource est une requête HTTP. Le poids de la page est la somme des octets transférés ; à ces deux mesures s'ajoute la taille du DOM, le nombre d'éléments que le navigateur doit construire et afficher.
Ces trois grandeurs pèsent sur les trois maillons du numérique :
| Mesure | Ce qu'elle sollicite | Pourquoi c'est un problème quand elle grossit |
|---|---|---|
| Poids transféré | Le réseau, et le forfait de l'utilisateur | Chargement lent en 4G faible, données facturées, plus de trafic pour l'hébergeur |
| Nombre de requêtes | Le serveur et le réseau | Plus de connexions, plus de traitements côté serveur et côté services tiers |
| Taille du DOM et JavaScript | Le terminal : son processeur et sa mémoire | Un vieux téléphone rame, l'utilisateur croit qu'il doit le changer |
Le dernier point est le plus important, parce que la fabrication des terminaux domine l'empreinte du numérique (chapitre 2). Un site qui exige un appareil récent contribue à l'obsolescence des appareils ; un site léger prolonge leur vie. C'est le premier objectif du RGESN.
Le diagnostic de la page de suivi
Le fil rouge de ce chapitre est la page publique de suivi des livraisons de Sorbier Logistique, hébergée sur srv-web, le serveur Apache de la DMZ, à l'adresse suivi.sorbier.example. Un client y tape son numéro de colis et voit où en est sa livraison. Le premier relevé, sans cache, donne ceci :
| Type de ressource | Requêtes | Poids transféré |
|---|---|---|
| HTML | 1 | 60 Ko |
| CSS (un framework complet et cinq feuilles d'extensions) | 6 | 210 Ko |
| JavaScript (jQuery, un carrousel, une carte, une fenêtre de discussion, deux outils de statistiques, des boutons de partage) | 38 | 1 150 Ko |
| Polices (deux familles, quatre graisses chacune) | 8 | 380 Ko |
| Images (une photo d'accueil de 4 000 pixels de large, les logos des partenaires, les vignettes du carrousel) | 59 | 2 380 Ko |
| Total | 112 | 4 180 Ko |
Le DOM compte 1 450 éléments. Sur un smartphone de cinq ans en 4G moyenne, la page met plusieurs secondes à devenir utilisable.
Commencer par le besoin
Avant d'optimiser une ressource, demande-toi si elle doit exister. Que vient faire le visiteur ? Taper un numéro et lire un statut. Tout le reste se discute.
| Élément | Question | Décision |
|---|---|---|
| Carrousel de cinq photos | Quelqu'un le regarde-t-il ? Les statistiques montrent que presque personne ne dépasse la première image | Une seule photo, plus petite |
| Fenêtre de discussion | Quelques conversations par mois, toutes sur le même sujet (« où est mon colis ? »), auquel la page répond déjà | Supprimée, remplacée par un lien vers le formulaire de contact |
| Carte interactive de l'entrepôt | Les clients ne viennent pas à l'entrepôt | Une adresse en texte et un lien vers un service de cartes |
| Deux outils de statistiques | Ils mesurent la même chose | Un seul, configuré au minimum |
| Boutons de partage sur les réseaux sociaux | Qui partage le suivi de son colis ? | Supprimés |
C'est la logique des critères 1.1 (utilité), 4.3 (parcours de navigation optimisé) et 4.6 (contenus porteurs d'information) du RGESN. Chaque fonctionnalité retirée, c'est du poids en moins, mais aussi du code en moins à maintenir, à mettre à jour et à sécuriser.
Les images, premier poste de poids
Les images représentaient plus de la moitié du poids. Quatre réglages suffisent souvent à les diviser par quatre.
1. Le bon format. Chaque type d'image a son format.
| Contenu | Format conseillé | Pourquoi |
|---|---|---|
| Photo | AVIF ou WebP, avec un JPEG de secours si nécessaire | À qualité égale, nettement plus légers que le JPEG ; pris en charge par tous les navigateurs actuels |
| Logo, icône, pictogramme, schéma | SVG | Du texte vectoriel : quelques kilo-octets, net à toutes les tailles |
| Capture d'écran avec du texte, image à aplats | PNG ou WebP sans perte | Le JPEG fait baver le texte |
| Animation courte | Vidéo (MP4, WebM) plutôt que GIF | Un GIF animé pèse souvent plusieurs fois plus que la même séquence en vidéo |
2. La bonne taille. La photo d'accueil faisait 4 000 pixels de large pour un affichage à 800 pixels au plus, soit 1 200 pixels réels sur un écran haute densité : le navigateur téléchargeait onze fois trop de pixels. Avec les attributs srcset et sizes, il choisit lui-même le fichier adapté à l'écran (images responsives).
3. La bonne compression. Règle la qualité à l'œil, image par image : une photo d'illustration supporte une compression forte. En ligne de commande, l'outil cwebp (paquet webp sous Debian) convertit et redimensionne :
# Photo redimensionnée à 1 200 pixels de large (hauteur proportionnelle), qualité 75
cwebp -q 75 -resize 1200 0 entrepot.jpg -o entrepot-1200.webp
4. Le chargement différé. Une image située plus bas dans la page n'a pas besoin d'être téléchargée avant que l'utilisateur fasse défiler : l'attribut loading="lazy" s'en charge. Ne le mets jamais sur l'image principale du haut de page, qui doit s'afficher tout de suite. Déclare toujours width et height, pour que la mise en page ne saute pas pendant le chargement (WebP, AVIF et chargement différé).
<!-- Image principale : formats modernes, taille adaptée, pas de chargement différé -->
<picture>
<source type="image/avif" srcset="img/entrepot-800.avif 800w, img/entrepot-1200.avif 1200w"
sizes="(max-width: 800px) 100vw, 800px">
<source type="image/webp" srcset="img/entrepot-800.webp 800w, img/entrepot-1200.webp 1200w"
sizes="(max-width: 800px) 100vw, 800px">
<img src="img/entrepot-800.jpg" alt="Quai de chargement de l'entrepôt de Mâcon"
width="800" height="450">
</picture>
<!-- Logo d'un partenaire, plus bas dans la page : SVG et chargement différé -->
<img src="img/partenaire-transports-roux.svg" alt="Transports Roux"
width="160" height="48" loading="lazy">
Polices, CSS et JavaScript
Les polices. Chaque graisse d'une police est un fichier : deux familles en quatre graisses, c'est huit téléchargements avant d'afficher le texte correctement. La solution la plus sobre est la pile de polices système : le texte s'affiche avec la police déjà installée sur l'appareil, sans aucun téléchargement.
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
Si la charte graphique impose une police, garde une seule famille, deux graisses au plus, au format WOFF2, et ajoute font-display: swap pour que le texte s'affiche tout de suite avec une police de secours (critère 4.8 du RGESN).
Le CSS. Un framework CSS complet pour une page de trois blocs, c'est 200 Ko de règles dont la plupart ne servent pas. Écris le CSS dont la page a besoin, ou configure l'outil de construction pour retirer les règles inutilisées, puis minifie le fichier.
Le JavaScript. C'est la ressource la plus coûteuse pour le terminal : il faut la télécharger, mais aussi l'analyser et l'exécuter, ce qui occupe le processeur. Trois réflexes :
- Utiliser les éléments natifs du HTML avant une bibliothèque :
<details>et<summary>pour un accordéon,<dialog>pour une fenêtre modale,<input type="date">pour un calendrier. Ils fonctionnent sans script, au clavier et avec les lecteurs d'écran (critère 4.5 du RGESN). - Charger les scripts sans bloquer l'affichage, avec l'attribut
defer. - Limiter les requêtes pendant la saisie. Si le champ de suivi interroge le serveur à chaque frappe, un numéro de 11 caractères envoie 11 requêtes. Vérifie d'abord le format côté navigateur, puis attends que l'utilisateur ait fini de taper (critères 4.9 et 4.10).
<label for="numero">Numéro de colis (format SL-12345678)</label>
<input id="numero" name="numero" pattern="SL-[0-9]{8}" required autocomplete="off">
// N'appelle la fonction qu'après 300 ms sans nouvelle frappe
function debounce(fonction, delai) {
let minuteur;
return (...args) => {
clearTimeout(minuteur);
minuteur = setTimeout(() => fonction(...args), delai);
};
}
const champ = document.querySelector('#numero');
champ.addEventListener('input', debounce(() => {
if (champ.checkValidity()) chercherColis(champ.value); // aucune requête si le format est faux
}, 300));
Les services tiers et les vidéos
Un service tiers est une ressource chargée depuis un autre domaine : outil de statistiques, police hébergée ailleurs, vidéo intégrée, carte, bouton de réseau social, fenêtre de discussion. Chacun ajoute des requêtes que tu ne maîtrises pas, et la plupart déposent des traceurs, ce qui impose un consentement au titre du RGPD.
- Pèse chaque service tiers dans l'onglet Réseau, en filtrant par domaine. Le critère 4.4 du RGESN demande que l'utilisateur puisse décider de leur activation.
- Remplace une vidéo ou une carte intégrée par une façade : une image légère avec un bouton « Lancer la vidéo » ou « Afficher la carte ». Le lecteur et ses dizaines de requêtes ne se chargent qu'au clic.
- Préfère un outil de mesure d'audience sobre et configuré pour l'exemption de consentement, comme le permet la CNIL (mesure d'audience et RGPD).
- Pour tes propres vidéos : pas de lecture automatique,
preload="none"et une image d'aperçu (poster), une définition adaptée à la taille d'affichage, et si possible un mode « écoute seule » quand l'image n'apporte rien (critère 5.5).
Le cache et la compression, côté serveur
Le cache HTTP permet au navigateur de réutiliser une ressource déjà téléchargée. C'est l'en-tête Cache-Control, envoyé par le serveur, qui fixe la règle.
| Ressource | Règle | Effet |
|---|---|---|
Fichiers CSS et JS versionnés (site.3f9a2c1b.css, le nom change à chaque modification) | public, max-age=31536000, immutable | Gardés un an sans jamais redemander : un nouveau contenu aura un nouveau nom |
| Images, polices | public, max-age=2592000 | Gardées trente jours |
| Pages HTML | no-cache | Le navigateur redemande à chaque fois, mais le serveur répond 304 Not Modified, sans renvoyer la page, si elle n'a pas changé |
La compression réduit les ressources texte (HTML, CSS, JavaScript, JSON, SVG) avant leur envoi, souvent des deux tiers. Sur Debian, le module deflate d'Apache (compression gzip) est actif par défaut pour le HTML, le CSS et le JavaScript ; le module brotli, plus efficace, existe aussi. Les images AVIF, WebP ou JPEG sont déjà compressées : les recompresser ne sert à rien.
Enfin, HTTP/2 envoie toutes les ressources d'une page sur une seule connexion, et le critère 6.7 du RGESN demande de servir les ressources statiques depuis un même domaine pour en profiter. HTTP/2 n'est négocié qu'en HTTPS (les navigateurs ne le parlent que sur des adresses https://), et pas du tout avec le module MPM prefork : si Apache tourne en prefork, ce qui arrive quand le paquet libapache2-mod-php est installé, passe d'abord à PHP-FPM et au MPM event. Voici la configuration ajoutée sur srv-web :
# /etc/apache2/conf-available/suivi-performance.conf
Protocols h2 http/1.1
<IfModule mod_headers.c>
# Fichiers versionnés : un an en cache, sans revalidation
<FilesMatch "\.[0-9a-f]{8}\.(css|js)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
# Images et polices : trente jours
<FilesMatch "\.(avif|webp|jpg|svg|woff2)$">
Header set Cache-Control "public, max-age=2592000"
</FilesMatch>
# Pages HTML : toujours revalider (réponse 304 si rien n'a changé)
<FilesMatch "\.html$">
Header set Cache-Control "no-cache"
</FilesMatch>
</IfModule>
sudo a2enmod headers http2 # modules des en-têtes et de HTTP/2
sudo a2enconf suivi-performance # active le fragment de configuration
sudo apache2ctl configtest # doit répondre « Syntax OK »
sudo systemctl reload apache2
# Vérifier l'en-tête de cache et la compression d'un fichier CSS
curl -sI -H "Accept-Encoding: gzip" https://suivi.sorbier.example/css/site.3f9a2c1b.css \
| grep -i -E "cache-control|content-encoding"
cache-control: public, max-age=31536000, immutable
content-encoding: gzip
Le résultat
Après ces changements, la page de suivi pèse 690 Ko (contre 4 180) pour 28 requêtes (contre 112) et 610 éléments dans le DOM (contre 1 450). Elle n'a rien perdu de sa fonction : on y suit toujours son colis, plus vite. À la deuxième visite, presque tout vient du cache.
| Type de ressource | Requêtes | Poids transféré |
|---|---|---|
| HTML | 1 | 30 Ko |
| CSS | 1 | 25 Ko |
| JavaScript | 3 | 85 Ko |
| Polices | 0 | 0 Ko |
| Images | 23 | 550 Ko |
| Total | 28 | 690 Ko |
Le chapitre 7 transforme ces mesures en score EcoIndex : la page passe de la note F à la note C.
Exercices
Exercice 1 sur 5 Mesurer le gain Réussi À revoir
Reprends les deux tableaux de la page de suivi.
- De quel pourcentage le poids transféré a-t-il baissé ? Et le nombre de requêtes ?
- Quel type de ressource a le plus contribué à la baisse du poids, en kilo-octets ?
- Le critère 6.1 du RGESN cite en exemple l'objectif de passer de 2 Mo à 1 Mo et sous les 30 requêtes par page. La page optimisée respecte-t-elle ces ordres de grandeur ?
Voir la réponseMasquer la réponse de l'exercice 1
- Poids : 1 − 690 / 4 180 ≈ 0,835, soit une baisse de 83,5 % (la page est environ 6 fois plus légère). Requêtes : 1 − 28 / 112 = 0,75, soit 75 % de requêtes en moins.
- Les images : 2 380 − 550 = 1 830 Ko gagnés. Viennent ensuite le JavaScript (1 150 − 85 = 1 065 Ko), les polices (380 Ko) et le CSS (185 Ko).
- Oui : 690 Ko, sous la barre de 1 Mo, et 28 requêtes, sous les 30. Pour valider le critère, l'équipe doit encore fixer ces limites, les publier dans sa déclaration d'écoconception et les respecter dans les évolutions futures.
Tu avais trouvé ?
Exercice 2 sur 5 Choisir le format Réussi À revoir
Pour chaque image du site de Sorbier, choisis le format le plus adapté.
- Le logo de Sorbier Logistique, deux couleurs.
- La photo d'un quai de chargement.
- Une capture d'écran de l'espace client, avec beaucoup de texte, pour l'aide en ligne.
- Une animation de trois secondes qui montre comment trouver son numéro de colis.
- Douze pictogrammes de statut (en préparation, expédié, livré…).
Voir la réponseMasquer la réponse de l'exercice 2
- SVG : un logo vectoriel pèse quelques kilo-octets et reste net à toutes les tailles.
- AVIF ou WebP, en plusieurs largeurs avec
srcset, et un JPEG de secours si des navigateurs anciens doivent être pris en charge. - PNG ou WebP sans perte : le JPEG rendrait le texte flou. Redimensionne la capture à sa taille d'affichage.
- Une vidéo courte (MP4 ou WebM), sans lecture automatique, plutôt qu'un GIF animé, bien plus lourd.
- SVG, idéalement regroupés dans un seul fichier de symboles ou écrits directement dans le HTML, pour éviter douze requêtes.
Tu avais trouvé ?
Exercice 3 sur 5 Trouver les erreurs Réussi À revoir
Relève les pratiques non sobres dans cet extrait, et propose une correction pour chacune.
<link rel="stylesheet" href="https://cdn.example.com/framework-complet.min.css">
<link rel="stylesheet" href="https://fonts.example.com/css?family=Titre:300,400,600,700">
<script src="https://cdn.example.com/jquery.min.js"></script>
<video src="video/presentation-4k.mp4" autoplay muted loop></video>
<img src="img/entrepot.jpg" loading="lazy" alt="Entrepôt">
L'image entrepot.jpg est la grande photo du haut de page et mesure 4 000 pixels de large.
Voir la réponseMasquer la réponse de l'exercice 3
- Framework CSS complet chargé depuis un autre domaine : écrire ou extraire seulement le CSS utile, et le servir depuis le même domaine que la page (critère 6.7).
- Police en quatre graisses depuis un service tiers : passer aux polices système, ou héberger soi-même une seule famille en WOFF2, deux graisses au plus.
- jQuery chargé de façon bloquante, sans doute pour quelques lignes : réécrire ces lignes en JavaScript natif, et charger les scripts restants avec
defer. - Vidéo 4K en lecture automatique et en boucle : supprimer
autoplayetloop, ajouterpreload="none"et une imageposter, encoder dans une définition adaptée à la taille d'affichage. Se demander d'abord si cette vidéo est utile. - Image principale en
loading="lazy": la retirer, car l'image du haut de page doit se charger tout de suite. Ajouterwidthetheight, servir des versions redimensionnées en AVIF ou WebP avecsrcset, et un texte alternatif plus précis.
Tu avais trouvé ?
Exercice 4 sur 5 Combien de requêtes pendant la saisie ? Réussi À revoir
Un client tape au clavier le numéro SL-20261108, sans pause, en moins de 300 ms entre deux frappes.
- Combien de requêtes part-il vers le serveur si la recherche se lance à chaque événement
input? - Et avec la fonction
debouncede 300 ms du chapitre, sans le testcheckValidity()? - Le client tape ensuite
SL-2026et s'arrête une seconde pour retrouver la suite, puis tape1108. Combien de requêtes avecdebounceseul ? Et avecdebounceetcheckValidity()?
Voir la réponseMasquer la réponse de l'exercice 4
- 11 requêtes : une par caractère tapé, dont 10 pour des numéros incomplets.
- 1 requête : chaque frappe relance le minuteur, qui ne se déclenche que 300 ms après la dernière.
- Avec
debounceseul : 2 requêtes, une après la pause (pourSL-2026, un numéro incomplet) et une à la fin. AveccheckValidity()en plus : 1 requête, carSL-2026ne respecte pas le motifSL-[0-9]{8}et n'est pas envoyé.
Tu avais trouvé ?
Exercice 5 sur 5 Écrire les règles de cache Réussi À revoir
Pour chaque fichier servi par srv-web, donne la valeur de Cache-Control adaptée et justifie.
index.html, la page d'accueil, modifiée plusieurs fois par mois.assets/app.8c41d2e7.js, produit par l'outil de construction.img/entrepot-1200.avif, une photo qui ne change pas.api/colis/SL-20261108, la réponse JSON qui donne le statut d'un colis.
Voir la réponseMasquer la réponse de l'exercice 5
no-cache: le navigateur revalide à chaque visite et reçoit une réponse 304 sans contenu si la page n'a pas changé. Il voit tout de suite une nouvelle version.public, max-age=31536000, immutable: le nom contient une empreinte du contenu, donc un fichier modifié aura un autre nom. On peut le garder un an sans risque.public, max-age=2592000(trente jours) : la photo change rarement ; si elle change, il faudra lui donner un nouveau nom ou accepter un délai.no-store, ou au plus une durée très courte : le statut d'un colis change et il est propre à un client. Il ne doit pas être gardé par un cache partagé (privateau minimum). C'est au serveur de mettre en cache le calcul s'il est coûteux (chapitre 5).
Tu avais trouvé ?