Créer un thème sombre facilement
- Écrit le
- 11 février 2025
- ·
- 5 minutes de lecture
Créer un site web en 2025 sans proposer de thème sombre c'est condamner à l'aveuglement cette frange de la population qui parcourt le Web essentiellement dans le noir, sous la couette ou encore en boîte de nuit.
Bref, c'est pratiquement inenvisageable. Le souci c'est que créer un thème sombre qui tient la route n'est pas une mince affaire. J'ai eu le loisir de m'en rendre compte en créant ce site que vos yeux délicats parcourent en ce moment.
Le CSS moderne est là pour vous
L'avènement des thèmes sombre commence à dater un peu. Ça fait bien 5 ans qu'il est devenu bon ton de proposer thème clair et thème sombre lorsque l'on créé un site web ou une application. C'était initialement périlleux sans un minimum de JavaScript, mais il est aujourd'hui possible de s'en passer totalement.
L'usage de la fonction light-dark
combinée à la propriété color-scheme
est ce qui m'est apparu comme le plus facile pour commencer :
:root {
color-scheme: light dark;
}
body {
color: light-dark(#333b3c, #efefec);
background-color: light-dark(#efedea, #223a2c);
}
Ces 8 lignes suffisent comme base.
- La propriété
color-scheme: light dark
indique que c'est le thème préféré par l'utilisateur qui sera utilisé par défaut. - La fonction
light-dark()
retourne dynamiquement la couleur correspondant au thème actif. Si le thème est clair, c'est la première valeur qui sera utilisée, et si le thème est sombre, c'est la seconde valeur.
Difficile de faire plus simple.
Il vous suffit d'utiliser la fonction light-dark()
à chaque fois qu'une couleur doit s'adapter au thème.
Saupoudrez de quelques variables CSS
Cependant lorsque la quantité de code CSS croît, cela devient difficile à maintenir.
Heureusement, là encore, le CSS moderne — et plus particulièrement les variables — est là pour nous faciliter la vie :
:root {
color-scheme: light dark;
--color-background-dark: #0a0a0a;
--color-background-light: #fff;
--color-background: light-dark(var(--color-background-light), var(--color-background-dark));
--color-text-dark: #E8E5E3;
--color-text-light: #171717;
--color-text: light-dark(var(--color-text-light), var(--color-text-dark));
}
body {
background-color: var(--color-background);
color: var(--color-text);
}
C'est un peu plus verbeux initialement, mais ça simplifie grandement l'usage. Une fois vos variantes de couleur déclarées dans le bloc :root
, il vous suffit d'utiliser dans vos composants la variable résultante de la fonction light-dark()
, en l'occurrence var(--color-background)
et var(--color-text)
.
Appliquez cette recette pour toutes vos couleurs et n'y songez plus.
Ajouter un theme switcher
Désolé pour l'anglicisme mais je ne trouve pas de traduction satisfaisante.
Jusqu'à maintenant, on a ajouté le code nécessaire pour s'adapter au thème choisi par l'utilisateur au niveau de son système ou de son navigateur, mais il est impossible d'en changer dynamiquement lors de la navigation.
Pour ce faire, on devra passer par la case JavaScript, mais quelques lignes suffiront.
Il existe de multiples possibilité d'y parvenir mais cet excellent article sur HTMHell propose une solution que j'ai trouvé particulièrement séduisante.
L'idée principale est de déplacer l'instruction color-scheme: light dark;
du CSS au <head>
de la page, et de faire varier ce paramètre entre light
et dark
avec un bouton.
:root {
color-scheme: light dark;
--color-background-dark: #0a0a0a;
--color-background-light: #fff;
--color-background: light-dark(var(--color-background-light), var(--color-background-dark));
--color-text-dark: #E8E5E3;
--color-text-light: #171717;
--color-text: light-dark(var(--color-text-light), var(--color-text-dark));
}
Dans le code HTML :
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sports Almanac 1950-2000</title>
<meta name="color-scheme" content="dark light">
Ajoutez ensuite un bouton pour chaque thème :
<button class="switch-theme" data-theme="light">Thème clair</button>
<button class="switch-theme" data-theme="dark">Thème sombre</button>
Puis un peu de JavaScript pour modifier le color-scheme
dynamiquement :
const colorScheme = document.querySelector('meta[name=color-scheme]');
const switchThemeButtons = document.querySelectorAll('.switch-theme');
switchThemeButtons.forEach((button) => {
button.addEventListener('click', () => {
colorScheme.content = button.dataset.theme;
});
});
Et voilà le résultat :
Sauvegarder le choix
Pour avoir le theme switcher parfait, il manque une dernière chose : mémoriser le choix de l'utilisateur. L'utilisation du Local Storage est parfait pour cela.
Il y a deux scénarios à prendre en considération :
- Lors du changement de thème, il faut sauvegarder le choix de l'utilisateur dans le Local Storage.
- Lors du chargement du site, il faut restaurer le choix qu'à fait l'utilisateur précédemment ou basculer sur la valeur par défaut.
Sauvegarder
Une seule ligne à ajouter:
const colorScheme = document.querySelector('meta[name=color-scheme]');
const switchThemeButtons = document.querySelectorAll('.switch-theme');
switchThemeButtons.forEach((button) => {
button.addEventListener('click', () => {
colorScheme.content = button.dataset.theme;
localStorage.setItem('colorScheme', button.dataset.theme);
});
});
Restaurer
Il y a une petite subtilité à prendre en compte pour assurer une expérience optimale : il faut restaurer le choix de l'utilisateur avant que la page ne s'affiche, sans quoi il risque d'y avoir un effet de clignotement. Le site va d'abord s'afficher avec le thème par défaut, et après quelques millisecondes il va passer au thème sauvegardé. Pas terrible.
Pour éviter cet effet désagréable, ce code doit idéalement être exécuté au tout début du <body>
:
<body>
<script>
const savedColorScheme = localStorage.getItem('colorScheme');
if (['light', 'dark', 'dark light'].includes(savedColorScheme)) {
const colorScheme = document.querySelector('meta[name=color-scheme]');
colorScheme.content = savedColorScheme;
}
</script>
<!-- Reste de la page -->
</body>
Et voilà ! Il ne reste plus qu'à trouver une façon originale de présenter les boutons.