Implémentation du mode sombre dans les applications React à l'aide de composants de style

Publié: 2022-03-10
Résumé rapide ↬ Le mode clair est une convention dans la plupart des applications Web et mobiles. Cependant, dans le développement moderne, nous avons vu à quel point le mode sombre, qui affiche du texte clair et des éléments d'interface sur un fond sombre, devient rapidement une préférence des utilisateurs. Dans cet article, nous apprendrons comment implémenter efficacement le mode sombre dans une application React sur une simple page Web, en utilisant la bibliothèque de composants de style et en tirant parti de certaines fonctionnalités de React telles que les crochets. Nous discuterons également des avantages et des inconvénients du mode sombre et pourquoi il devrait être adopté.

L'une des fonctionnalités logicielles les plus demandées est le mode sombre (ou mode nuit, comme d'autres l'appellent). Nous voyons le mode sombre dans les applications que nous utilisons tous les jours. Des applications mobiles aux applications Web, le mode sombre est devenu vital pour les entreprises qui souhaitent prendre soin des yeux de leurs utilisateurs.

Le mode sombre est une fonctionnalité supplémentaire qui affiche principalement des surfaces sombres dans l'interface utilisateur. La plupart des grandes entreprises (telles que YouTube, Twitter et Netflix) ont adopté le mode sombre dans leurs applications mobiles et Web.

Bien que nous n'allions pas approfondir React et les composants stylés, une connaissance de base de React, CSS et des composants stylés serait utile. Ce tutoriel profitera à ceux qui cherchent à améliorer leurs applications Web en s'adressant à ceux qui aiment le mode sombre.

StackOverflow annonce le mode sombre sur Twitter
StackOverflow annonce le mode sombre sur Twitter ( Grand aperçu )

Quelques jours avant la rédaction de cet article, StackOverflow a annoncé la sortie du mode sombre, donnant aux utilisateurs la possibilité de basculer entre les deux modes.

Le mode sombre réduit la fatigue oculaire et aide lorsque vous travaillez longtemps sur un ordinateur ou un téléphone portable.

Qu'est-ce que le mode sombre ?

Le mode sombre est le jeu de couleurs de toute interface qui affiche du texte clair et des éléments d'interface sur un fond sombre, ce qui rend l'écran un peu plus facile à regarder sur les téléphones portables, les tablettes et les ordinateurs. Le mode sombre réduit la lumière émise par l'écran, tout en maintenant les rapports de contraste de couleur minimum requis pour la lisibilité.

Plus après saut! Continuez à lire ci-dessous ↓

Pourquoi devriez-vous vous soucier du mode sombre ?

Le mode sombre améliore l'ergonomie visuelle en réduisant la fatigue oculaire, en ajustant l'écran aux conditions d'éclairage actuelles et en offrant une facilité d'utilisation la nuit ou dans des environnements sombres.

Avant d'implémenter le mode sombre dans notre application, examinons ses avantages.

Economie de batterie

Le mode sombre dans les applications Web et mobiles peut prolonger la durée de vie de la batterie d'un appareil. Google a confirmé que le mode sombre sur les écrans OLED a été d'une grande aide pour la durée de vie de la batterie.

Par exemple, à 50 % de luminosité, le mode sombre de l'application YouTube permet d'économiser environ 15 % d'énergie en plus sur l'écran qu'un fond blanc plat. Avec une luminosité d'écran de 100 %, l'interface sombre permet d'économiser 60 % de l'énergie de l'écran.

Le mode sombre est magnifique

Le mode sombre est magnifique et peut considérablement améliorer l'attrait de l'écran.

Alors que la plupart des produits optent pour ce look blanc fade similaire, le mode sombre offre quelque chose de différent qui semble mystérieux et nouveau.

Il offre également d'excellentes opportunités pour présenter du contenu graphique tel que des tableaux de bord, des images et des photos d'une manière nouvelle.

Twitter en mode sombre ou clair
La beauté du mode sombre de Twitter sur le mode clair ( Grand aperçu )

Maintenant que vous savez pourquoi vous devriez implémenter le mode sombre dans votre prochaine application Web, plongeons dans les composants stylés, qui sont la ressource déterminante de ce didacticiel.

Le mode sombre est le jeu de couleurs de toute interface qui affiche du texte clair et des éléments d'interface sur un fond sombre, ce qui le rend un peu plus facile à regarder sur les téléphones mobiles, les tablettes et les ordinateurs.

"

Que sont les composants de style ?

Tout au long de cet article, nous utiliserons très souvent la bibliothèque de composants de style. Il y a toujours eu de nombreuses façons de styliser une application Web moderne. Il existe la méthode traditionnelle de style au niveau du document, qui comprend la création d'un fichier index.css et sa liaison au code HTML ou le style à l'intérieur du fichier HTML.

Beaucoup de choses ont changé récemment dans la façon dont les applications Web sont stylisées, depuis l'introduction de CSS-in-JS.

CSS-in-JS fait référence à un modèle dans lequel CSS est composé à l'aide de JavaScript. Il utilise des littéraux de modèle balisés pour styliser les composants dans un fichier JavaScript.

Pour en savoir plus sur CSS-in-JS, consultez l'article d'Anna Monus sur le sujet.

styled-components est une bibliothèque CSS-in-JS qui vous permet d'utiliser toutes les fonctionnalités de CSS que vous aimez, y compris les requêtes multimédias, les pseudo-sélecteurs et l'imbrication.

Pourquoi des composants stylés ?

styled-components a été créé pour les raisons suivantes :

  • Pas de nom de classe enfer
    Au lieu de vous gratter la tête pour trouver un nom de classe pour un élément, styled-components génère des noms de classe uniques pour vos styles. Vous n'aurez jamais à vous soucier des fautes d'orthographe ou de l'utilisation de noms de classe qui n'ont aucune signification.
  • Utiliser des accessoires
    styled-components nous permet d'étendre les propriétés de style à l'aide du paramètre props , couramment utilisé dans React - affectant ainsi dynamiquement la sensation d'un composant via l'état de l'application.
  • Prend en charge la syntaxe Sass
    L'écriture de la syntaxe Sass prête à l'emploi sans avoir à configurer de préprocesseurs ou d'outils de construction supplémentaires est possible avec les composants stylés. Dans vos définitions de style, vous pouvez utiliser le caractère & pour cibler le composant actuel, utiliser des pseudo-sélecteurs et expérimenter l'imbrication.
  • Thématisation
    styled-components bénéficie d'une prise en charge complète des thèmes en exportant un composant wrapper ThemeProvider . Ce composant fournit un thème à tous les composants React en lui-même via l'API Context. Dans l'arborescence de rendu, tous les composants stylés auront accès au thème fourni, même lorsqu'ils sont à plusieurs niveaux. Au fur et à mesure que nous poursuivons dans ce didacticiel, nous examinerons plus en détail les fonctionnalités de thématisation des composants stylés.

Pour en savoir plus sur les avantages des composants stylés, consultez l'article de Kris Guzman.

Implémentation du mode sombre

Dans cet article, nous allons implémenter le mode sombre sur une simple page Web de type YouTube.

Pour continuer, assurez-vous de cloner le référentiel d'origine à partir de la branche de starter .

Mise en place

Installons toutes les dépendances dans notre fichier package.json . Depuis le terminal, exécutez la commande suivante :

 npm install

Une fois l'installation réussie, exécutez npm start . Voici à quoi ressemble la page Web sans le mode sombre implémenté.

La page Web à utiliser, sans mode sombre
La page Web à utiliser, sans mode sombre. ( Grand aperçu )

Pour installer styled-components , dans votre terminal, exécutez npm install styled-components .

Mise en œuvre

Pour implémenter le mode sombre, nous devons créer quatre composants différents.

  • Theme
    Celui-ci contient les propriétés de couleur de nos thèmes clairs et sombres.
  • GlobalStyles
    Celui-ci contient les styles globaux pour l'ensemble du document.
  • Toggler
    Cela contient l'élément de bouton qui bascule la fonctionnalité.
  • useDarkMode
    Ce crochet personnalisé gère la logique derrière le changement de thème et la persistance de notre thème dans localStorage.

Composant thématique

Dans le dossier src , vous verrez des composants dans le dossier components . Créez un fichier Themes.js et ajoutez-y le code suivant.

 export const lightTheme = { body: '#FFF', text: '#363537', toggleBorder: '#FFF', background: '#363537', } export const darkTheme = { body: '#363537', text: '#FAFAFA', toggleBorder: '#6B8096', background: '#999', }

Ici, nous avons défini et exporté des objets lightTheme et darkTheme avec des variables de couleur distinctes. N'hésitez pas à expérimenter et à personnaliser les variables à votre convenance.

Composant globalStylesglobalStyles Component

En restant dans votre dossier de components , créez un fichier globalStyles.js et ajoutez le code suivant :

 import { createGlobalStyle} from "styled-components" export const GlobalStyles = createGlobalStyle` body { background: ${({ theme }) => theme.body}; color: ${({ theme }) => theme.text}; font-family: Tahoma, Helvetica, Arial, Roboto, sans-serif; transition: all 0.50s linear; } `

Nous avons importé createGlobalStyle à partir de composants stylés. La méthode createGlobalStyle remplace la méthode injectGlobal désormais obsolète de styled-components version 3. Cette méthode génère un composant React qui, une fois ajouté à votre arborescence de composants, injectera des styles globaux dans le document, dans notre cas, App.js .

Nous avons défini un composant GlobalStyle et attribué des propriétés d'arrière- background et de color aux valeurs de l'objet de thème. Ainsi, chaque fois que nous basculerons la bascule, les valeurs changeront en fonction des objets de thème sombre ou de thème clair que nous transmettons à ThemeProvider (qui sera créé plus tard, au fur et à mesure).

La propriété de transition de 0.50s permet à ce changement de se produire un peu plus en douceur, de sorte que lorsque nous basculons d'avant en arrière, nous pouvons voir les changements se produire.

Création d'une fonctionnalité de basculement de thème

Pour implémenter la fonctionnalité de basculement de thème, nous n'avons besoin d'ajouter que quelques lignes de code. Dans le fichier App.js , ajoutez le code suivant (notez que le code en surbrillance est ce que vous devez ajouter) :

 import React, { useState, useEffect } from "react";
import {ThemeProvider} from "styled-components"; import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes"
import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
 const [theme, setTheme] = useState('light'); const themeToggler = () => { theme === 'light' ? setTheme('dark') : setTheme('light') }
 useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []); return (
 <ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}> <> <GlobalStyles/>
 <div className="App">
 <button onClick={themeToggler}>Switch Theme</button>
 { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div>
 </> </ThemeProvider>
); }; export default App;

Le code en surbrillance est celui qui vient d'être ajouté à App.js . Nous avons importé ThemeProvider à partir de styled styled-components . ThemeProvider est un composant d'assistance de la bibliothèque de composants de style qui fournit un support de thème. Ce composant d'assistance injecte un thème dans tous les composants React en dessous de lui-même via l'API Context.

Dans l'arborescence de rendu, tous les composants stylés auront accès au thème fourni, même lorsqu'ils sont à plusieurs niveaux. Consultez la section "Thématisation".

Ensuite, nous importons le wrapper ./components/Globalstyle GlobalStyle Enfin, à partir du haut, nous importons à la fois les objets lightTheme et darkTheme depuis ./components/Themes .

Pour que nous puissions créer une méthode de basculement, nous avons besoin d'un état contenant la valeur de couleur initiale de notre thème. Nous créons donc un état de theme et définissons l'état initial sur light , à l'aide du hook useState .

Maintenant, pour la fonctionnalité de basculement.

La méthode themeToggler utilise un opérateur ternaire pour vérifier l'état du theme et bascule entre sombre ou clair en fonction de la valeur de la condition.

ThemeProvider , un composant d'assistance de composants de style, encapsule tout dans l'instruction de return et injecte tous les composants en dessous. Rappelez-vous que nos GlobalStyles injectent des styles globaux dans nos composants ; par conséquent, il est appelé à l'intérieur du composant wrapper ThemeProvider .

Enfin, nous avons créé un bouton avec un événement onClick qui lui attribue notre méthode themeToggler .

Voyons le résultat jusqu'à présent.

Mode sombre implémenté sans persistance.
Mode sombre implémenté sans persistance ( Grand aperçu )

Notre fichier App.js doit être refactorisé ; une grande partie de son code n'est pas DRY. (DRY signifie « ne vous répétez pas », un principe de base du développement logiciel visant à réduire la répétition.) Toute la logique semble être dans App.js ; c'est une bonne pratique de séparer notre logique par souci de clarté. Nous allons donc créer un composant qui gère la fonctionnalité de basculement.

Basculer le composant

Toujours dans le dossier des components , créez un fichier Toggler.js et ajoutez-y le code suivant :

 import React from 'react' import { func, string } from 'prop-types'; import styled from "styled-components" const Button = styled.button` background: ${({ theme }) => theme.background}; border: 2px solid ${({ theme }) => theme.toggleBorder}; color: ${({ theme }) => theme.text}; border-radius: 30px; cursor: pointer; font-size:0.8rem; padding: 0.6rem; } \`; const Toggle = ({theme, toggleTheme }) => { return ( <Button onClick={toggleTheme} > Switch Theme </Button> ); }; Toggle.propTypes = { theme: string.isRequired, toggleTheme: func.isRequired, } export default Toggle;

Pour garder les choses propres, nous avons stylé notre bouton bascule dans le composant Toggle , en utilisant la fonction styled de styled-components.

C'est purement pour la présentation; vous pouvez styliser le bouton comme bon vous semble.

À l'intérieur du composant Toggle , nous passons deux accessoires :

  • le theme fournit le thème actuel (clair ou foncé) ;
  • la fonction toggleTheme sera utilisée pour basculer entre les thèmes.

Ensuite, nous renvoyons le composant Button et attribuons une fonction toggleTheme à l'événement onClick .

Enfin, nous utilisons propTypes pour définir nos types, en veillant à ce que notre theme soit une string et isRequired , tandis que notre toggleTheme est func et isRequired .

Utilisation de crochets personnalisés ( useDarkMode )

Lors de la construction d'une application, l'évolutivité est primordiale, ce qui signifie que notre logique métier doit être réutilisable, afin que nous puissions l'utiliser dans de nombreux endroits et même dans différents projets.

C'est pourquoi il serait bon de déplacer notre fonctionnalité de basculement vers un composant séparé. Pour cela, nous créerions notre propre crochet personnalisé.

Créons un nouveau fichier nommé useDarkMode.js dans le dossier des components et déplaçons notre logique vers ce fichier, avec quelques ajustements. Ajoutez le code suivant au fichier :

 import { useEffect, useState } from 'react'; export const useDarkMode = () => { const [theme, setTheme] = useState('light'); const setMode = mode => { window.localStorage.setItem('theme', mode) setTheme(mode) }; const themeToggler = () => { theme === 'light' ? setMode('dark') : setMode('light') }; useEffect(() => { const localTheme = window.localStorage.getItem('theme'); localTheme && setTheme(localTheme) }, []); return [theme, themeToggler] };

Nous avons ajouté quelques éléments ici.

  • setMode
    Nous utilisons localStorage pour persister entre les sessions dans le navigateur. Ainsi, si un utilisateur a choisi le thème sombre ou clair, c'est ce qu'il obtiendra lors de sa prochaine visite sur l'application ou s'il recharge la page. Par conséquent, cette fonction définit notre état et transmet le theme à localStorage .
  • themeToggler
    Cette fonction utilise un opérateur ternaire pour vérifier l'état du thème et bascule entre sombre ou clair en fonction de la vérité de la condition.
  • useEffect
    Nous avons implémenté le crochet useEffect pour vérifier le montage des composants. Si l'utilisateur a déjà sélectionné un thème, nous le transmettrons à notre fonction setTheme . Au final, nous retournerons notre theme , qui contient le theme choisi et la fonction themeToggler pour basculer entre les modes.

Je pense que vous conviendrez que notre composant en mode sombre a l'air élégant.

Passons à App.js pour la touche finale.

 import React, { useState, useEffect } from "react"; import {ThemeProvider} from "styled-components";
import {useDarkMode} from "./components/useDarkMode"
import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes" import Toggle from "./components/Toggler" import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
 const [theme, themeToggler] = useDarkMode(); const themeMode = theme === 'light' ? lightTheme : darkTheme;
useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []); return (
 <ThemeProvider theme={themeMode}>
 <> <GlobalStyles/> <div className="App">
 <Toggle theme={theme} toggleTheme={themeToggler} />
 { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> </> </ThemeProvider> ); }; export default App;

Le code en surbrillance est nouvellement ajouté à App.js .

Tout d'abord, nous importons notre hook personnalisé, déstructurons les props theme et themeToggler , et le définissons avec la fonction useDarkMode .

Notez que la méthode useDarkMode remplace notre état de theme , qui était initialement dans App.js .

Nous déclarons une variable themeMode , qui affiche un thème clair ou sombre en fonction de l'état du mode theme à ce moment-là.

Maintenant, notre composant wrapper ThemeProvider est affecté à notre variable themeMode récemment créée à l'accessoire de theme .

Et enfin, à la place du bouton habituel, nous passons le composant Toggle .

N'oubliez pas que dans notre composant Toggle , nous avons défini et stylisé un bouton et leur avons transmis theme et toggleTheme en tant qu'accessoires. Donc, tout ce que nous avons à faire est de transmettre ces accessoires de manière appropriée au composant Toggle , qui agira comme notre bouton dans App.js .

Oui! Notre mode sombre est activé et il persiste, ne changeant pas de couleur lorsque la page est actualisée ou visitée dans un nouvel onglet.

Voyons le résultat en action :

Mode sombre implémenté, mais avec un bug dans la couleur du bouton lors du rechargement du navigateur.
Mode sombre implémenté, mais avec un bug dans la couleur du bouton lors du rechargement du navigateur. ( Grand aperçu )

Presque tout fonctionne bien, mais il y a une petite chose que nous pouvons faire pour rendre notre expérience splendide. Passez au thème sombre puis rechargez la page. Voyez-vous que la couleur bleue du bouton se charge avant le gris pendant un bref instant ? Cela se produit parce que notre hook useState lance initialement le thème light . Après cela, useEffect s'exécute, vérifie localStorage , puis définit le theme sur dark . Passons à notre hook personnalisé useDarkMode.js et ajoutons un peu de code :

 import { useEffect, useState } from 'react'; export const useDarkMode = () => { const [theme, setTheme] = useState('light');
 const [mountedComponent, setMountedComponent] = useState(false)
 const setMode = mode => { window.localStorage.setItem('theme', mode) setTheme(mode) }; const themeToggler = () => { theme === 'light' ? setMode('dark') : setMode('light') }; useEffect(() => { const localTheme = window.localStorage.getItem('theme'); localTheme ? setTheme(localTheme) : setMode('light')
 setMountedComponent(true)
 }, []); return [theme, themeToggler, }, []); return [theme, themeToggler, mountedComponent ]
};

Le code en surbrillance est le seul ajouté à useDarkMode.js . Nous avons créé un autre état nommé mountedComponent et défini la valeur par défaut sur false à l'aide du crochet useState . Ensuite, à l'intérieur du crochet useEffect , nous définissons l'état monté de mountedComponent sur true à l'aide de setMountedComponent . Enfin, dans le tableau de return , nous mountedComponent l'état du composant monté.

Enfin, ajoutons un peu de code dans App.js pour que tout fonctionne.

 import React, { useState, useEffect } from "react"; import {ThemeProvider} from "styled-components"; import {useDarkMode} from "./components/useDarkMode" import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes" import Toggle from "./components/Toggler" import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
 const [theme, themeToggler, mountedComponent] = useDarkMode();
 const themeMode = theme === 'light' ? lightTheme : darkTheme; useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []);
 if(!mountedComponent) return <div/>
 return ( <ThemeProvider theme={themeMode}> <> <GlobalStyles/> <div className="App"> <Toggle theme={theme} toggleTheme={themeToggler} /> { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> </> </ThemeProvider> ); }; export default App;

Nous avons ajouté notre état mountedComponent en tant que prop dans notre crochet useDarkMode , et nous avons vérifié si notre composant était monté, car c'est ce qui se passe dans le crochet useEffect . Si cela ne s'est pas encore produit, nous rendrons un div vide.

Voyons le résultat de notre page Web en mode sombre.

Résultat final du mode sombre
Résultat final du mode sombre ( Grand aperçu )

Maintenant, vous remarquerez qu'en mode sombre, lorsque la page se recharge, la couleur du bouton ne change pas.

Conclusion

Le mode sombre devient de plus en plus une préférence des utilisateurs, et son implémentation dans une application Web React est beaucoup plus facile lorsque vous utilisez le wrapper de thème ThemeProvider dans des composants stylés. Allez-y et expérimentez avec des composants stylés lorsque vous implémentez le mode sombre ; vous pouvez ajouter des icônes au lieu d'un bouton.

Veuillez partager vos commentaires et votre expérience avec la fonctionnalité de thème dans les composants de style dans la section des commentaires ci-dessous. J'aimerais voir ce que vous proposez!

Le référentiel de prise en charge de cet article est disponible sur GitHub. Consultez-le également sur CodeSandbox.

Les références

  • « Documentation », composants de style
  • "Créez un mode sombre de votre application à l'aide de composants stylés", Tom Nolan, Medium