Pour ajouter du style à votre application React, vous avez certainement jusqu'ici utilisé du CSS. Pour gagner du temps de développement sur le CSS nous pouvons même utiliser des bibliothèques comme Bootstrap ou encore Tailwind. Cependant, vous est-il déjà arrivé de réutiliser le nom d'une classe CSS dans un autre composant sans faire exprès ? Ou bien encore de trouver du style appliqué à un élément sans comprendre d'où il venait ? Si ça vous est déjà arrivé, vous devez savoir à quel point c'est frustrant ! 😬
L'enjeu de scoper notre style aux composants concernés est réel.
Hmm… "scoper", encore un anglicisme que je n'ai jamais vu... ?
Le scope correspond aux parties de notre code qui ont accès à un élément, comme une variable, ou une classe CSS. Il peut être global (comme c'est le cas pour les classes CSS dont je vous parlais il y a quelques instants), ou bien concerner une partie spécifique du code.
Pour scoper le style, il existe des solutions, telles que des méthodologies d'architecture de CSS ou bien des outils spécifiques comme Sass (qui requiert un préprocesseur). Mais depuis quelques années, le CSS in JS émerge comme l'une des solutions à notre problème.
Découvrez le CSS in JS
Comme son nom l'indique, le CSS in JS est généré… avec du JavaScript. Il sera inséré dans le DOM dans un élément <style>
.
Ah mais je vois, c'est comme l'inline style qu'on avait vu au chapitre "Incorporez du style et des assets à votre projet", dans le cours précédent.
... Eh bien non. L'inline style est inséré dans le DOM sur l'attribut style
d'un élément spécifique (souvenez-vous, on fait <div style={{ color: 'red' }} />
). Par ailleurs, l'inline style ne permet pas d'utiliser les pseudo-selectors. Ce n'est pas pareil pour le CSS in JS, avec lequel on peut utiliser autant de pseudo-selectors que nécessaire (on le verra un plus tard dans ce chapitre).
Mais avec le CSS in JS, on garde l'idée que le style est attaché à un composant spécifique, directement dans le même fichier. Beaucoup plus simple lorsqu'il faut supprimer ou modifier du style déjà existant, n'est-ce pas ?
Il existe plusieurs solutions de CSS in JS, avec leurs syntaxes propres. Ici nous allons nous intéresser à la bibliothèque styled components. 💅
Commençons dès maintenant par installer la bibliothèque avec yarn add styled-components
:
Tada !
Penchons-nous dès maintenant sur le style que nous allons pouvoir créer ! 👀
Appliquez la logique styled components
Dans styled components, la principale chose à comprendre est que tout est composant. Pour voir cela, créons dès maintenant notre premier styled component (styled composant).
Dans Card/index.jsx
, créons donc le style pour le label
.
On commence par ajouter l'import de styled-components puis nous créons notre composant CardLabel
de la manière suivante :
import styled from 'styled-components'
const CardLabel = styled.span``
Et on a réutilisé CardLabel
directement dans le JSX :
<CardLabel>{label}</CardLabel>
Mais qu'est-ce que c'est que cette syntaxe bizarre ? 😬
Pas de panique ! Ici, styled-components
utilise des templates literals, que vous pouvez voir dans la documentation Mozilla. Vous pouvez écrire votre CSS directement à l'intérieur. Ce qui nous donne :
const CardLabel = styled.span`
color: #5843e4;
font-size: 22px;
font-weight: bold;
`
Profitons-en pour ajouter du style à notre image. Cette fois-ci, toujours dans le même fichier Card/index.jsx
, on a :
const CardImage = styled.img`
height: 80px;
width: 80px;
border-radius: 50%;
`
… qu'on utilise dans le code :
<CardImage src={picture} alt="freelance" />
Bravo à vous ! Vous avez généré des éléments span
et img
auxquels vous avez appliqué du style avec styled-components
! 🎉 Vous vous en doutez, ça ne s'arrête pas à span
et img
: vous pouvez ainsi générer tous les éléments existants du DOM… mais pas que.
Par exemple, comment faire si je veux styliser un élément qui vient d'une bibliothèque ?
Styled components prévoit ce cas ! Prenons l'exemple de Header/index.jsx
. Pour cela, il nous suffit de faire :
import { Link } from 'react-router-dom'
import styled from 'styled-components'
const StyledLink = styled(Link)`
padding: 15px;
color: #8186a0;
text-decoration: none;
font-size: 18px;
`
function Header() {
return (
<nav>
<StyledLink to="/">Accueil</StyledLink>
<StyledLink to="/survey/1">Questionnaire</StyledLink>
<StyledLink to="/freelances">Profils</StyledLink>
</nav>
)
}
export default Header
Essayez ce code pour voir le rendu vous-même – pas mal, n'est-ce pas ?
Passez des props dans votre CSS
C'est bien beau, nous avons créé nos styled components et nous les avons utilisés, mais quels autres avantages tire-t-on du fait d'écrire notre style avec du JS ?
... Eh bien justement, on utilise du JS. 😎 On va pouvoir passer des props à nos composants directement depuis notre composant React.
Voyons voir concrètement ce que cela donne dans notre Header
.
<StyledLink to="/survey/1" $isFullLink>
Faire le test
</StyledLink>
Ici on passe la prop $isFullLink
. Ce qui nous permet d'utiliser la prop directement dans le style :
const StyledLink = styled(Link)`
padding: 15px;
color: #8186a0;
text-decoration: none;
font-size: 18px;
${(props) =>
props.$isFullLink &&
`color: white; border-radius: 30px; background-color: #5843E4;`}
`
C'est quoi ce $
?
Eh bien, cela permet de signaler à styled-components
que notre prop nous sert pour le style, et qu'elle ne doit pas être passée dans le DOM.
Ce $
est uniquement nécessaire pour passer une prop si le composant en question est un composant React, comme ici pour Link
(et non un élément HTML). Si mon styled component était basé sur une simple balise a
, je pourrais totalement utiliser la prop isFullLink
sans le $
.
Voyons l’utilisation du state en prop de plus près dans le screencast ci-dessous :
Pas maaaal ! 🤩
Utilisez des variables
Vous voyez, dans notre dernier snippet de code juste au-dessus du screencast, on a encore utilisé la couleur violette #5843E4
. Qui dit JS dit aussi qu'on peut utiliser des variables, et c'est ce que nous allons faire : nous allons utiliser des variables pour stocker nos couleurs !
Vous pourriez tout simplement déclarer un objet colors
qui reprend toutes les couleurs de notre application, mais il est considéré comme une bonne pratique de créer un thème géré par styled-components
.
On crée donc un dossier /utils
directement dans src/
, dans lequel on met un dossier /style
. On y crée notre fichier colors.js
, ce qui nous donne :
├── assets │ └── profile.png ├── components │ ├── Card │ │ └── index.jsx │ ├── Error │ │ └── index.jsx │ └── Header │ └── index.jsx ├── index.jsx ├── pages │ ├── Freelances │ │ └── index.jsx │ ├── Home │ │ └── index.jsx │ ├── Results │ │ └── index.jsx │ └── Survey │ └── index.jsx └── utils └── style └── colors.js
Dans colors.js
, on définit nos couleurs :
const colors = {
primary: '#5843E4',
secondary: '#8186A0',
backgroundLight: '#F9F9FC',
}
export default colors
Pour l'utiliser, il nous suffit de l'importer directement dans notre template string :
const StyledLink = styled(Link)`
padding: 15px;
color: #8186a0;
text-decoration: none;
font-size: 18px;
${(props) =>
props.$isFullLink &&
`color: white; border-radius: 30px; background-color: ${colors.primary};`}
`
Et on a bien ce qu'on voulait. 💅
Par contre, comment faire si je veux styliser mon composant au survol de la souris ?
Eh bien, c'est très simple ici puisque les pseudosélecteurs fonctionnent dans nos styled components.
Pour mettre tout ça en pratique, on va retourner sur nos Cards
. On y ajoutera un peu de style pour que l'effet de hover soit plus visible. Dans pages/freelances.jsx
, on met :
const CardsContainer = styled.div`
display: grid;
gap: 24px;
grid-template-rows: 350px 350px;
grid-template-columns: repeat(2, 1fr);
`
... qu'on utilise tout de suite dans le même fichier :
function Freelances() {
return (
<div>
<h1>Freelances 👩💻👨💻👩💻</h1>
<CardsContainer>
{freelanceProfiles.map((profile, index) => (
<Card
key={`${profile.name}-${index}`}
label={profile.jobTitle}
title={profile.name}
/>
))}
</CardsContainer>
</div>
)
}
Puis dans Card/index.jsx
, on peut créer un effet d'ombre au survol de la souris. Pour ça, on crée un CardWrapper
qui vient remplacer notre précédente div
:
function Card({ label, title, picture }) {
return (
<CardWrapper>
<CardLabel>{label}</CardLabel>
<CardImage src={picture} alt="freelance" />
<span>{title}</span>
</CardWrapper>
)
}
Et on définit CardWrapper comme suit :
const CardWrapper = styled.div`
display: flex;
flex-direction: column;
padding: 15px;
background-color: ${colors.backgroundLight};
border-radius: 30px;
width: 350px;
transition: 200ms;
&:hover {
cursor: pointer;
box-shadow: 2px 2px 10px #e2e3e9;
}
`
La syntaxe &:hover
nous permet d'accéder au pseudosélecteur du survol de la souris, et on a bien l'effet souhaité ! 🤩
Créez un style global
Nous avons déjà vu beaucoup de choses avec styled components. Encore une fois, nous ne pouvons pas tout couvrir dans ce chapitre, mais avant de conclure j'aimerais que nous créions un style global. Cela nous permettra de créer un style de base, notamment pour la police ou pour d'autres propriétés CSS.
Pour cela, dans index.jsx
à la racine de notre projet, vous pouvez créer un composant GlobalStyle :
const GlobalStyle = createGlobalStyle`
div {
font-family: 'Trebuchet MS', Helvetica, sans-serif;
}
`
Et vous l'importez tout simplement dans vos composants :
<Router>
<GlobalStyle />
<Header />
…
</Router>
Et voilà ! Ensemble, nous avons utilisé styled-components
pour styliser notre application ! 🎉
Exercez-vous
C'est maintenant le moment de vous exercer en autonomie sur la bibliothèque styled-components
. Vous trouverez la base de code nécessaire pour commencer cet exercice sur la branche P1C4-begin
du projet sur GitHub.
Cette fois-ci, vous devrez vous appuyer sur la maquette Figma et créer le style pour :
le header (intégration du logo, position des liens) ;
la page d'accueil (intégration du texte, de l'illustration, du background, etc.) ;
la page Profils (texte au-dessus des Cards) ;
la page d'erreur.
Comme d'habitude, vous trouverez la solution de cet exercice sur la branche P1C4-solution
. 🤫
En résumé
Styled components est une bibliothèque de CSS in JS qui permet de créer du style en appliquant une logique de composants.
Les template strings utilisées écrites entre
``
permettent d'utiliser des variables et de passer des props.Il est possible de créer un style global avec
createGlobalStyle
.
Bravo à vous, maintenant que vous avez intégré du style, l'application que vous codez pour Shiny Agency commence vraiment à prendre forme ! ✨
Dans le prochain chapitre, vous allez tester vos connaissances avec le quiz de cette partie. Alors, bonne chance à vous ! 🍀