Cet article sera le troisième et dernier d'une série de trois :
- Images et polices personnalisées (https://dev.to/alexandrecantin/optimiser-vos-pages-web-quelques-reflexes-indispensables-g79)
- JavaScript et pré-chargement de ressources (https://dev.to/alexandrecantin/accelerer-vos-pages-web-quelques-reflexes-partie-2-2oh3)
- Contenus animés et LightHouse (cet article)
🎬 5 - Contenus animées : .mp4 et GIF
5.1 - Privilégier les vidéos .mp4 sur les GIF
Cette recommandation peut sembler contre-intuitive mais, dans le cas des GIFs, il est nécessaire de les convertir en .mp4 pour diminuer leur poids.
En effet, bien que le format GIF soit un format d'image, il s'agit d'une succession d'images et peut donc être assimilé à une vidéo. Toutefois, contrairement au format .mp4, le format GIF est moins bien optimisé.
Prenons par exemple, le GIF ci-dessous dont le poids est de 5.1 Mo :
Après une conversion en .mp4 (via https://video.online-convert.com/fr/convertir/gif-en-mp4 par exemple), son poids se retrouve divisé par 5 pour atteindre 1.1 Mo.
Pour ensuite obtenir un rendu et comportement similaires à ceux d'une image GIF, il est nécessaire d'ajouter les attributs autoplay loop muted playsinline
à la balise video
:
<video autoplay loop muted playsinline>
<source src="video.mp4" type="video/mp4" />
</video>
Si vous souhaitez aller plus loin, il est aussi possible d'adapter le rendu en fonction de la qualité de la connexion Internet de l'utilisateur avec navigator.connection.effectiveType
pour, par exemple, renvoyer une image (optimisée bien entendu) à la place d'une vidéo :
if(navigator.connection.effectiveType === "4g")
return <Video src="animate-background.mp4" />
return <img src="background.png" alt="" />
Malheureusement, cette fonctionnalité est pour le moment très mal supportée par les différents navigateurs :
5.2 - Attention au player Youtube
Youtube fournit un moyen simple d'héberger mais aussi d'intégrer des vidéos dans vos pages via une iframe. Toutefois, cette dernière va télécharger tous un ensemble de fichiers pour un total de 584 Ko !
Bien sûr, à ce temps de téléchargement s'additionne le temps de parsing, compilation et d'exécution du navigateur. Qui plus est, l'utilisateur paiera ce prix qu'il visionne ou non cette vidéo !
Comment éviter cela ? Deux solutions sont envisageables.
5.2.1 - Le lazy loading
La première solution renvoie au chapitre relatif au lazy loading des images : l'iframe la plus optimale reste celle qu'on ne télécharge pas. De même, les deux solutions évoquées sont aussi d'actualités, à savoir :
1 - Utiliser lazysizes en remplaçant l'attribut src
par data-src
:
<iframe frameborder="0" allowfullscreen=""
data-src="//www.youtube.com/embed/ZfV-aYdU4uE">
</iframe>
2 - Utiliser l'attribut loading="lazy"
(dont le support - ou son manque de support - reste identique aux images) :
<iframe frameborder="0" allowfullscreen="" src="//www.youtube.com/embed/ZfV-aYdU4uE" loading="lazy"></iframe>
Toutefois, le problème n'est résolu qu'à moitié : dès que la vidéo apparaît à l'écran de l'utilisateur, nous récupérons l'ensemble des 584 Ko de JavaScript.
5.2.2 - Un faux lecteur vidéo
L'idée, au premier abord, peut sembler saugrenue mais permet d'obtenir le résultat escompté : remplacer le player Youtube par un bouton contenant une image de pré-visualisation associée à une icône de lecture. En cas de clic, nous basculons ensuite sur l'iframe de Youtube en lecture automatique (via autoplay=1
).
Note : pour réaliser ce composant, nous utiliserons React mais une transposition vers des équivalents Svelte, Vue ou Angular est facilement envisageable.
Ce composant accueillera deux paramètres que seront :
- l'identifiant de la vidéo Youtube
- le titre de vidéo (pour l'accessibilité - notamment ceux avec un lecteur d'écran)
Pour utiliser ce composant, nous procéderons de la sorte :
<YoutubeVideo id="dQw4w9WgXcQ" title="Never gonna give you up" />
Tout d'abord, nous commencerons par créer le bouton en question :
import React from "react";
function YoutubeVideo({ id, title }) {
return (
<button
type="button"
title={`Vidéo Youtube : ${title}`}
style={buttonStyle}
onClick={startVideo}
>
<img style={imgStyle} src={`https://img.youtube.com/vi/${id}/hqdefault.jpg`} alt="" />
<img style={youtubeIconStyle} src="youtube-icon.svg" alt="" />
</button>
);
}
export default YoutubeVideo;
En ajoutant un peu de style à notre bouton, nous allons :
- indiquer les dimensions de la vidéo, dimensions qui seront identiques pour la vidéo et le bouton
- centrer l'icône de lecture verticalement et horizontalement
- ajuster l'image de pré-visualisation pour qu'elle occupe la totalité de l'espace disponible. D'ailleurs, concernant cette image, vous pouvez remarquer qu'elle provient directement de Youtube; l'image d'une vidéo pouvant être récupérée à l'adresse suivante :
https://img.youtube.com/vi/[IDENTIFIANT_VIDEO]/hqdefault.jpg
.
/* Dimensions de la vidéo et du bouton */
const style = {
width: "100%",
height: "350px"
};
/* Centrer l'icône Youtube (entre autres...) */
const buttonStyle = {
...style,
position: "relative",
overflow: "hidden",
cursor: "pointer",
display: "flex",
justifyContent: "center",
alignItems: "center",
border: "none"
};
/* Image de pré-visualisation pour occuper tout l'espace */
const imgStyle = {
width: "100%",
height: "100%",
position: "absolute",
zIndex: 1
};
/* Placer l'icône au-dessus de celle de pré-visualisation */
const youtubeIconStyle = {
zIndex: 2
};
Pour le moment, nous obtenons un bouton qui ne fait simplement rien... mais qui ressemble fortement à la preview d'une vidéo Youtube :
La suite consistera à ajouter une variable au sein de notre composant, nommée showVideo
, gérant l'affichage de l'iframe. Elle sera à false
par défaut et signifiera que l'on affichera le bouton de pré-visualisation. Au clic sur le bouton, showVideo
deviendra true
et occasionnera le démarrage de la vidéo.
...
function YoutubeVideo({ id, imgSrc, title }) {
// On utilise les hooks React
const [showVideo, setShowVideo] = useState(false);
function startVideo() {
setShowVideo(true);
}
...
return (
<button
onClick={startVideo} // <=== Action au clic
type="button"
title={`Vidéo Youtube : ${title}`}
style={buttonStyle}
>
<img style={imgStyle} src={`https://img.youtube.com/vi/${id}/hqdefault.jpg`} alt="" />
<img style={youtubeIconStyle} src="youtube-icon.svg" alt="" />
</button>
);
}
La dernière étape consistera à renvoyer l'iframe Youtube si showVideo
a une valeur égale à true
. Noter l'ajout de autoplay=1
après l'URL de la vidéo Youtube, c'est ce paramètre qui permet de démarrer la vidéo sans nécessiter de second clic par l'utilisateur :
if (showVideo) {
return (
<div>
<iframe
sandbox="allow-scripts allow-same-origin allow-presentation"
title={`Vidéo Youtube : ${title}`}
src={`https://www.youtube.com/embed/${id}?autoplay=1&rel=0`}
frameBorder="0"
allow="autoplay; encrypted-media"
allowFullScreen
style={style}
/>
</div>
);
}
Et c'est aussi simple que cela, nous venons de créer un composant n'affichant (et téléchargeant) le lecteur Youtube uniquement si cela est nécessaire.
J'aurai bien voulu convertir ce GIF en mp4 mais dev.to n'accepte pas les vidéos 😔
Au final, voici le code de notre composant au complet :
import React, { useState } from "react";
const style = {
width: "100%",
height: "350px"
};
const buttonStyle = {
...style,
position: "relative",
overflow: "hidden",
cursor: "pointer",
display: "flex",
justifyContent: "center",
alignItems: "center",
border: "none"
};
const imgStyle = {
width: "100%",
height: "100%",
position: "absolute",
zIndex: 1
};
const youtubeIconStyle = {
zIndex: 2
};
function YoutubeVideo({ id, title }) {
const [showVideo, setShowVideo] = useState(false);
function startVideo() {
setShowVideo(true);
}
if (showVideo) {
return (
<div>
<iframe
sandbox="allow-scripts allow-same-origin allow-presentation"
title={`Vidéo Youtube : ${title}`}
src={`https://www.youtube.com/embed/${id}?autoplay=1&rel=0`}
frameBorder="0"
allow="autoplay; encrypted-media"
allowFullScreen
style={style}
/>
</div>
);
}
return (
<button
type="button"
title={`Vidéo Youtube : ${title}`}
style={buttonStyle}
onClick={startVideo}
>
<img style={imgStyle} src={`https://img.youtube.com/vi/${id}/hqdefault.jpg`} alt="" />
<img style={youtubeIconStyle} src="youtube-icon.svg" alt="" />
</button>
);
}
export default YoutubeVideo;
Cette optimisation peut sembler s'apparenter à du bricolage mais le résultat est bien là : une diminution de plus de 500 Ko du poids de votre page et un téléchargement uniquement si l'utilisateur souhaite consulter la vidéo.
🧜🏻♀️ 6 - Lighthouse
Et s'il existait un outil testant l'ensemble de ces critères, voire plus ? Bonne nouvelle, cet outil existe et il se nomme Lighthouse !
Directement embarqué dans le navigateur Google Chrome ou disponible en ligne à l'adresse https://developers.google.com/web/tools/lighthouse#psi, Lighthouse regroupe tout un panel de tests mesurant la vitesse - entre autres - de votre page.
L'outil vous attribue ensuite un score sur 100 et des points d'améliorations.
Auditer et surveiller ces métriques régulièrement (une fois par mois par exemple) est un réflexe important pour vous assurer que votre site continue d'être performant au fur et à mesure de son évolution.
Je vous invite à tester votre site dès maintenant et, si vous ne l'avez jamais fait, des surprises vous attendent sûrement 😉 !
🚀 Conclusion
Nous voici arrivés à la fin de cette série d'articles consacrée à l'amélioration du chargement des pages Web. J'en profite pour vous remercier d'avoir pris le temps de la lire et j'espère qu'elle vous aura plu 🙂
Toutefois, ce billet n'a pas la prétention d'être exhaustif et d'autres optimisations aurait pu être abordées comme http2, les CDN... Je vous invite d'ailleurs à l'indiquer en commentaires 🙂.
Je vous remercie d'avoir pris le temps de lire cette série et j'espère que dorénavant, vous contribuerez à créer un web plus léger 😉.
🔰 Aller plus loin
Vidéos et articles
Voici un ensemble de ressources pour explorer l'univers de l'optimisation des chargements :
Fast load times : https://web.dev/fast/
Lazy-loading d'images et iframe : https://web.dev/native-lazy-loading/
Code-splitting in React : https://reactjs.org/docs/code-splitting.html#route-based-code-splitting
Web performance made easy (Google I/O '18) :
https://www.youtube.com/watch?v=Mv-l3-tJgGkSpeed at Scale: Web Performance Tips and Tricks from the Trenches (Google I/O ’19) : https://www.youtube.com/watch?v=YJGCZCaIZkQ
Sur Twitter
- Houssein Djirdeh : https://twitter.com/hdjirdeh
- Addy Osmani : https://twitter.com/addyosmani
- Katie Hempenius : https://twitter.com/katiehempenius
- Paul Irish : https://twitter.com/paul_irish
- Lighthouse : https://twitter.com/____lighthouse
Top comments (0)