Quand j'ai créé ma dernière app, "simple baby diary" (une app qui sert à consigner tous les repas & siestes de bébé), je voulais ajouter une option dans l'app pour forcer un thème dans l'app, sombre ou lumineux.
Quelque chose comme ça :
Comment ça fonctionne ? Ben par défaut, une app Ionic utilise les media queries pour savoir quand utiliser le thème sombre :
Sauf que... impossible de trouver une solution simple. C'est visiblement impossible de forcer le prefers-color-scheme sans changer le code.
Du coup je me suis lancé en quête d'une solution simple. Et après quelques minutes, j'ai réalisé.... ben pourquoi ne pas juste prendre le contrôle de ce qui se passe ?
Qu'est ce que je veux en fait ?
un mode "auto" par défaut, qui changera le thème selon le mode du téléphone
être capable d'activer le thème sombre en permanence
être capable d'activer le thème light en permanence
Le code par défaut d'une app Ionic empêche de forcer le thème sombre. Il fallait donc changer la logique.
J'ai donc ajouté 3 classes possibles à mettre sur le "body" de l'app :
auto, qui va utiliser le thème configuré du téléphone (en fonction du prefer-colors-scheme)
dark, pour forcer le thème sombre
light, pour forcer le thème light
A partir de là, tout se fait en quelques étapes simplistes. Déjà on va split le fichier SCSS en 4 :
The fichier variables.scss contiendra le thème light par défaut.
Ensuite, on crée le fichier variables-dark.scss. Lui contiendra quelques mixins avec la config sombre :
Maintenant, je veux inclure ces mixins dans 2 situations :
quand il y a la classe dark sur body
quand il y a la classe auto et que le thème du téléphone (prefers-color-scheme) est sombre
Pour faire ça, j'appelle mes mixins dans le code de theme-dark.scss :
Comme vous le voyez, ce code fera exactement ce que je veux, à savoir inclure ces mixins si le body a la classe dark, ou si le prefers-color-scheme vaut dark et le body a la classe auto.
Et avoir fait des mixins évite d'avoir à répéter tout le css dans les deux cas.
Ca ressemble à une solution plutôt élégante non ? Il n'y a plus qu'à changer la classe sur le body dans mon code.
Ah et n'oubliez pas d'ajouter ces fichiers SCSS à votre fichier projet angular.json ou project.json :
Maintenant, pour ajouter la classe au body, je vais juste créer un service ColorSchemeService qui va ajouter/enlever la class, via le @Inject(DOCUMENT) :
Evidemment les perfectionnistes me diront "eh ce serait mieux d'utiliser un ENUM pour ton thème de couleurs, et éviter de le stocker dans le local storage", mais ici je ne cherche pas à faire du code parfait, juste du code qui marche 🤷
Au final, j'ai plus qu'à charger mon thème dans le constructor du AppComponent :
Et quand je clique sur un des boutons pour forcer le thème :
And... voilà !
Ah une dernière chose, par défaut le thème light ne déclare pas ses color et background color (surement un bug passager, j'espère qu'il sera corrigé rapidement). Du coup je vous conseille d'ajouter ça dans theme.scss :