Catégories
Plugin et site web

Comment utiliser des composants stylisés dans React – Smashing Magazine

A propos de l'auteur

Adebiyi Adedotun Lukman est un ingénieur UI / Frontend basé à Lagos, au Nigeria, qui adore également UI / UX Design pour l'amour des grands logiciels. Quand …
Plus à propos
Adebiyi

Bien que l’approche axée sur les composants ait ouvert une nouvelle frontière dans la façon dont nous construisons des applications Web, elle n’est pas sans imperfections, l’une étant sa convivialité et son évolutivité avec CSS. Cela a donné naissance à une nouvelle façon de construire et de gérer nos styles dans un spécifique au composant manière, autrement connu sous le nom de CSS-in-JS.

Les composants stylisés sont un outil CSS-in-JS qui comble le fossé entre les composants et le style, offrant de nombreuses fonctionnalités pour vous permettre de vous familiariser avec les composants de style d'une manière fonctionnelle et réutilisable. Dans cet article, vous découvrirez les bases des composants stylisés et comment les appliquer correctement à vos applications React. Vous devriez avoir déjà travaillé sur React avant de suivre ce tutoriel. Si vous recherchez différentes options pour styliser les composants React, vous pouvez consulter notre précédent article sur le sujet.

Au cœur de CSS se trouve la capacité de cibler n'importe quel élément HTML – globalement – quelle que soit sa position dans l'arborescence DOM. Cela peut être un obstacle lorsqu'ils sont utilisés avec des composants, car les composants exigent, dans une mesure raisonnable, une colocalisation (c'est-à-dire en gardant les éléments tels que les états et le style) plus près de l'endroit où ils sont utilisés (appelée localisation).

Selon les propres mots de React, les composants stylisés sont "primitives visuelles pour les composants», Et leur objectif est de nous offrir une manière flexible de styliser les composants. Le résultat est un couplage étroit entre les composants et leurs styles.

Remarque: les composants stylisés sont disponibles à la fois pour React et React Native, et même si vous devriez absolument consulter le guide React Native, nous nous concentrerons ici sur les composants stylisés pour React.

Pourquoi des composants stylisés?

En plus de vous aider à définir des styles, les composants stylisés incluent les fonctionnalités suivantes:

  • Préfixation automatique du fournisseur
    Vous pouvez utiliser les propriétés CSS standard et les composants stylisés ajouteront des préfixes de fournisseur s'ils sont nécessaires.
  • Noms de classe uniques
    Les composants stylisés sont indépendants les uns des autres et vous n'avez pas à vous soucier de leurs noms car la bibliothèque gère cela pour vous.
  • Élimination des styles morts
    Les composants stylisés suppriment les styles inutilisés, même s'ils sont déclarés dans votre code.
  • et beaucoup plus.

Installation

L'installation de composants stylisés est facile. Vous pouvez le faire via un CDN ou avec un gestionnaire de packages tel que Yarn…

yarn add styled-components

… Ou npm:

npm i styled-components

Notre démo utilise create-react-app.

Commençant

La première chose que vous remarquerez peut-être à propos des composants stylisés est leur syntaxe, qui peut être décourageante si vous ne comprenez pas la magie des composants stylisés. Pour résumer, les composants stylisés utilisent les littéraux de modèle JavaScript pour combler le fossé entre les composants et les styles. Ainsi, lorsque vous créez un composant stylisé, vous créez en fait un composant React avec des styles. Cela ressemble à ceci:

import styled from "styled-components";

// Styled component named StyledButton
const StyledButton = styled.button`
  background-color: black;
  font-size: 32px;
  color: white;
`;

function Component() {
  // Use it like any other component.
  return  Login ;
}

Ici, StyledButton est le composant stylé, et il sera rendu sous forme de bouton HTML avec les styles contenus. styled est une méthode utilitaire interne qui transforme le style de JavaScript en CSS réel.

En HTML et CSS bruts, nous aurions ceci:

button {
  background-color: black;
  font-size: 32px;
  color: white;
}

Si les composants stylisés sont des composants React, pouvons-nous utiliser des accessoires? Oui nous pouvons.

Adaptation basée sur des accessoires

Les composants stylisés sont fonctionnel, nous pouvons donc facilement styliser les éléments de manière dynamique. Supposons que notre page comporte deux types de boutons, l’un avec un arrière-plan noir et l’autre bleu. Nous n'avons pas besoin de créer deux composants stylisés pour eux; nous pouvons adapter leur style en fonction de leurs accessoires.

import styled from "styled-components";

const StyledButton = styled.button`
  min-width: 200px;
  border: none;
  font-size: 18px;
  padding: 7px 10px;
  /* The resulting background color will be based on the bg props. */
  background-color: ${props => props.bg === "black" ? "black" : "blue";
`;

function Profile() {
  return (
    
Button A Button B
) }

Car StyledButton est un composant React qui accepte les accessoires, nous pouvons attribuer une couleur d'arrière-plan différente en fonction de l'existence ou de la valeur du bg soutenir.

Vous remarquerez cependant que nous n’avons pas donné à notre bouton un type. Faisons cela:

function Profile() {
  return (
    <>
      
        Button A
      
       alert("clicked")}>
        Button B
      
    
  );
}

Les composants stylisés peuvent différencier les types d'accessoires qu'ils reçoivent. Ils savent que type est un attribut HTML, donc ils rendent réellement , lors de l'utilisation du bg prop dans leur propre traitement. Remarquez comment nous avons également attaché un gestionnaire d'événements?

En parlant d'attributs, une syntaxe étendue nous permet de gérer les accessoires en utilisant le attrs constructeur. Regarde ça:

const StyledContainer = styled.section.attrs((props) => ({
  width: props.width || "100%",
  hasPadding: props.hasPadding || false,
}))`
  --container-padding: 20px;
  width: ${(props) => props.width}; // Falls back to 100%
  padding: ${(props) =>
    (props.hasPadding && "var(--container-padding)") || "none"};
`;

Remarquez comment nous n'avons pas besoin d'un ternaire lors de la définition de la largeur? C'est parce que nous avons déjà défini une valeur par défaut pour cela avec width: props.width || "100%",. De plus, nous avons utilisé les propriétés personnalisées CSS parce que nous le pouvons!

Remarque: Si les composants stylisés sont des composants React et que nous pouvons passer des accessoires, pouvons-nous également utiliser des états? Le compte GitHub de la bibliothèque rencontre un problème pour résoudre ce problème.

Extension des styles

Imaginons que vous travailliez sur une page de destination et que vous ayez défini votre conteneur sur une certaine largeur maximale pour garder les choses centrées. Tu as un StyledContainer pour ça:

const StyledContainer = styled.section`
  max-width: 1024px;
  padding: 0 20px;
  margin: 0 auto;
`;

Ensuite, vous découvrez que vous avez besoin d'un conteneur plus petit, avec un remplissage de 10 pixels des deux côtés, au lieu de 20 pixels. Votre première pensée pourrait être de créer un autre composant de style, et vous avez raison, mais il ne vous faudra pas de temps avant de vous rendre compte que vous dupliquez des styles.

const StyledContainer = styled.section`
  max-width: 1024px;
  padding: 0 20px;
  margin: 0 auto;
`;

const StyledSmallContainer = styled.section`
  max-width: 1024px;
  padding: 0 10px;
  margin: 0 auto;
`;

Avant de continuer et de créer StyledSmallContainer, comme dans l'extrait de code ci-dessus, apprenons à réutiliser et à hériter des styles. C'est plus ou moins comme le spread l'opérateur travaille:

const StyledContainer = styled.section`
  max-width: 1024px;
  padding: 0 20px;
  margin: 0 auto;
`;

// Inherit StyledContainer in StyledSmallConatiner
const StyledSmallContainer = styled(StyledContainer)`
  padding: 0 10px;
`;

function Home() {
  return (
    
      

The secret is to be happy

); } function Contact() { return (

The road goes on and on

); }

Dans votre StyledSmallContainer, vous obtiendrez tous les styles de StyledContainer, mais le remplissage sera remplacé. Gardez à l'esprit que, en général, vous obtiendrez un élément de section pour StyledSmallContainer, parce que c’est ce que StyledContainer rend. Mais cela ne veut pas dire qu'il est sculpté dans la pierre ou immuable.

L'élément polymorphe «en tant que»

Avec le as accessoire polymorphe, vous pouvez échanger le fin élément qui est rendu. Un cas d'utilisation est celui où vous héritez des styles (comme dans le dernier exemple). Si, par exemple, vous préférez un div à un section pour StyledSmallContainer, vous pouvez passer le as prop à votre composant stylé avec la valeur de votre élément préféré, comme ceci:

function Home() {
  return (
    
      

It’s business, not personal

); } function Contact() { return (

Never dribble when you can pass

); }

Maintenant, StyledSmallContainer sera rendu comme un div. Vous pouvez même avoir un composant personnalisé comme valeur:

function Home() {
  return (
    
      

It’s business, not personal

); } function Contact() { return (

Never dribble when you can pass

); }

Ne le prenez pas pour acquis.

Syntaxe de type SCSS

Le préprocesseur CSS Stylis permet aux composants stylés de prendre en charge la syntaxe de type SCSS, telle que l'imbrication:

const StyledProfileCard = styled.div`
  border: 1px solid black;

  > .username {
    font-size: 20px;
    color: black;
    transition: 0.2s;

    &:hover {
      color: red;
    }

    + .dob {
      color: grey;
    }
  }
`;

function ProfileCard() {
  return (
    
      

John Doe

Date: 12th October, 2013

Male

); }

Animation

Les composants stylisés ont un keyframes assistant qui aide à construire des images clés d'animation (réutilisables). L'avantage ici est que les images clés seront détachées des composants stylisés et pourront être exportées et réutilisées là où c'est nécessaire.

import styled, {keyframes} from "styled-components";

const slideIn = keyframes`
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
`;

const Toast = styled.div`
  animation: ${slideIn} 0.5s cubic-bezier(0.4, 0, 0.2, 1) both;
  border-radius: 5px;
  padding: 20px;
  position: fixed;
`;

Style global

Alors que l’objectif initial de CSS-in-JS et, par extension, des composants stylisés est d’établir la portée des styles, nous pouvons également exploiter le style global des composants stylisés. Étant donné que nous travaillons principalement avec des styles étendus, vous pourriez penser que c'est un paramètre d'usine invariable, mais vous vous trompez. Pensez-y: qu'est-ce que le cadrage? Il est techniquement possible pour nous – au nom du style global – de faire quelque chose de similaire à ceci:

ReactDOM.render(
  
    
  ,
  document.getElementById("root")
);

Mais nous avons déjà une fonction d'assistance – createGlobalStyle – dont la seule raison d'être est le style global. Alors, pourquoi lui nier sa responsabilité?

Une chose que nous pouvons utiliser createGlobalStyle car c'est normaliser le CSS:

import {createGlobalStyle} from "styled-components";

const GlobalStyle = createGlobalStyle`
    /* Your css reset here */
`;

// Use your GlobalStyle
function App() {
  return (
    
); }

Remarque: Styles créés avec createGlobalStyle n'acceptez aucun enfant. En savoir plus dans la documentation.

À ce stade, vous vous demandez peut-être pourquoi nous devrions utiliser createGlobalStlye du tout. Voici quelques raisons:

  • Nous ne pouvons rien cibler en dehors du rendu racine sans lui (par exemple, html, body, etc.).
  • createGlobalStyle injecte des styles mais ne rend aucun élément réel. Si vous regardez attentivement le dernier exemple, vous remarquerez que nous n'avons spécifié aucun élément HTML à afficher. C'est cool car nous n'avons peut-être pas besoin de l'élément. Après tout, nous sommes préoccupés par les styles globaux. Nous ciblons les sélecteurs dans leur ensemble, pas des éléments spécifiques.
  • createGlobalStyle n'est pas limité et peut être affiché n'importe où dans notre application et sera applicable tant qu'il est dans le DOM. Pensez au concept, pas le structure.
import {createGlobalStyle} from "styled-components";

const GlobalStyle = createGlobalStyle`
  /* Your css reset here */

  .app-title {
    font-size: 40px;
  }
`;

const StyledNav = styled.nav`
    /* Your styles here */
`;

function Nav({children}) {
  return (
    
      
      {children}
    
  );
}

function App() {
  return (
    
); }

Si vous pensez à la structure, alors app-title ne doit pas être conçu comme défini dans GlobalStyle. Mais cela ne fonctionne pas de cette façon. Où que vous choisissiez de rendre votre GlobalStyle, il sera injecté lorsque votre composant sera rendu.

Faites attention: createGlobalStyles ne sera rendu que si et quand il est dans le DOM.

Aide CSS

Nous avons déjà vu comment adapter les styles en fonction des accessoires. Et si on voulait aller un peu plus loin? La fonction d'assistance CSS permet d'y parvenir. Supposons que nous ayons deux champs de saisie de texte avec des états: vide et actif, chacun avec une couleur différente. Nous pouvons le faire:

const StyledTextField = styled.input`
  color: ${(props) => (props.isEmpty ? "none" : "black")};
`;

Tout va bien. Par la suite, si nous devons ajouter un autre état de remplissage, nous devrons modifier nos styles:

const StyledTextField = styled.input`
  color: ${(props) =>
    props.isEmpty ? "none" : props.active ? "purple" : "blue"};
`;

Maintenant, l'opération ternaire devient de plus en plus complexe. Et si nous ajoutions un autre état à nos champs de saisie de texte ultérieurement? Ou que faire si nous voulons donner à chaque état des styles supplémentaires, autres que la couleur? Pouvez-vous imaginer resserrer les styles dans l'opération ternaire? le css helper est utile.

const StyledTextField = styled.input`
  width: 100%;
  height: 40px;

  ${(props) =>
    (props.empty &&
      css`
        color: none;
        backgroundcolor: white;
      `) ||
    (props.active &&
      css`
        color: black;
        backgroundcolor: whitesmoke;
      `)}
`;

Ce que nous avons fait, c'est en quelque sorte élargi notre syntaxe ternaire pour accueillir plus de styles et avec une syntaxe plus compréhensible et organisée. Si la déclaration précédente semble erronée, c'est parce que le code essaie d'en faire trop. Alors, prenons du recul et affinons:

const StyledTextField = styled.input`
width: 100%;
height: 40px;

// 1. Empty state
${(props) =>
  props.empty &&
  css`
    color: none;
    backgroundcolor: white;
  `}

// 2. Active state
${(props) =>
  props.active &&
  css`
    color: black;
    backgroundcolor: whitesmoke;
  `}

// 3. Filled state
${(props) =>
  props.filled &&
  css`
    color: black;
    backgroundcolor: white;
    border: 1px solid green;
  `}
`;

Notre raffinement divise le style en trois morceaux différents gérables et faciles à comprendre. C’est une victoire.

StyleSheetManager

Comme l'assistant CSS, StyleSheetManager est une méthode d'aide pour modifier la façon dont les styles sont traités. Il faut certains accessoires – comme disableVendorPrefixes (vous pouvez consulter la liste complète) – qui vous aident à désactiver les préfixes de fournisseur de sa sous-arborescence.

import styled, {StyleSheetManager} from "styled-components";

const StyledCard = styled.div`
  width: 200px;
  backgroundcolor: white;
`;

const StyledNav = styled.div`
  width: calc(100% - var(--side-nav-width));
`;

function Profile() {
  return (
    
This is a card
); }

disableVendorPrefixes est passé comme accessoire à . Ainsi, les composants stylisés enveloppés par seraient désactivés, mais pas ceux de .

Débogage plus facile

Lors de la présentation de composants stylisés à l'un de mes collègues, l'une de leurs plaintes était qu'il était difficile de localiser un élément rendu dans le DOM – ou dans React Developer Tools, d'ailleurs. C'est l'un des inconvénients des composants stylisés: en essayant de fournir des noms de classe uniques, il attribue des hachages uniques aux éléments, qui se trouvent être cryptiques, mais cela rend le displayName lisible pour un débogage plus facile.

import React from "react";
import styled from "styled-components";
import "./App.css";

const LoginButton = styled.button`
  background-color: white;
  color: black;
  border: 1px solid red;
`;

function App() {
  return (
    
Login
); }

Par défaut, les composants stylisés sont rendus LoginButton comme dans le DOM, et comme LoginButton dans React Developer Tools, ce qui facilite le débogage. Nous pouvons basculer le displayName booléen si nous ne voulons pas de ce comportement. Cela nécessite une configuration Babel.

Remarque: Dans la documentation, le package babel-plugin-styled-components est spécifié, ainsi qu'un .babelrc fichier de configuration. Le problème avec ceci est que, parce que nous utilisons create-react-app, nous ne pouvons pas configurer beaucoup de choses à moins d’éjecter. C'est là qu'interviennent les macros Babel.

Nous devrons installer babel-plugin-macros avec npm ou Yarn, puis créez un babel-plugin-macros.config.js à la racine de notre application, avec le contenu:

module.exports = {
  styledComponents: {
    displayName: true,
    fileName: false,
  },
};

Avec le fileName valeur inversée, le displayName sera précédé du nom du fichier pour une précision encore plus unique.

Nous devons également maintenant importer depuis le macro:

// Before
import styled from "styled-components";

// After
import styled from "styled-components/macro";

Conclusion

Maintenant que vous pouvez composer votre CSS par programmation, n'abusez pas de cette liberté. Pour ce que cela vaut, faites de votre mieux pour maintenir la cohérence de vos composants stylisés. N'essayez pas de composer des conditionnels lourds, et ne supposez pas que tout doit être un composant stylisé. De plus, ne faites pas trop d'abstraction en créant des composants de style naissant pour des cas d'utilisation que vous devinez seulement quelque part au coin de la rue.

Autres ressources

  1. Documentation, composants stylisés
  2. «Construire un système de composants réutilisables avec React.js et des composants stylisés», Lukas Gisder-Dubé
  3. Utilisation avec Next.js
  4. Utilisation avec Gatsby
Éditorial fracassant(ks, ra, yk, al, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *