Cours JavaScript et React · Module 14: Styles avancés
Comparer les approches de stylage - Carte de la galaxie
Dans cette leçon7
Nous avons maintenant trois outils puissants pour le stylage dans notre arsenal. Il est temps de les comparer et de comprendre quand utiliser chacun d'eux. C'est comme choisir un vaisseau spatial -- chacun a ses points forts et ses meilleurs cas d'usage.
Tableau comparatif
| Caractéristique | CSS Modules | Styled-components | Tailwind CSS |
|---|---|---|---|
| Isolation | Automatique (classes uniques) | Automatique (classes uniques) | Aucune (classes globales) |
| Styles dynamiques | Limité (variables CSS) | Complet (props + JS) | clsx/cn + conditions |
| Taille du bundle | Petite | Plus grande (JS à l'exécution) | Petite (purge) |
| Courbe d'apprentissage | Faible | Moyenne | Moyenne |
| Theming | Variables CSS | ThemeProvider | tailwind.config |
| Pseudo-classes | Oui (CSS pur) | Oui (syntaxe &) | Oui (préfixes) |
| Responsivité | Media queries | Media queries | Préfixes (md:, lg:) |
| SSR | Sans accroc | Nécessite une configuration | Sans accroc |
Quand utiliser les CSS Modules ?
Les CSS Modules sont idéaux quand :
- Tu veux une solution simple sans bibliothèques supplémentaires
- L'équipe connaît bien le CSS pur
- Le projet utilise Create React App ou Next.js (support intégré)
- La performance est importante (zéro JS à l'exécution)
- Tu migres depuis un projet CSS existant
1// CSS Modules -- du CSS simple et familier
2import styles from './Card.module.css';
3
4function Card({ title }) {
5 return <div className={styles.card}><h2>{title}</h2></div>;
6}Quand utiliser Styled-components ?
Styled-components sont idéaux quand :
- Tu as besoin de styles très dynamiques (dépendant des props, de l'état)
- Tu construis une bibliothèque de composants avec des styles intégrés
- Tu veux un theming avancé avec changement de thème
- Le projet est orienté composants (les styles = une partie du composant)
1// Styled-components -- les styles comme partie du composant
2const Card = styled.div`
3 background: ${({ variant }) => variant === 'dark' ? '#0a0a2e' : '#ffffff'};
4 padding: ${({ theme }) => theme.spacing.lg};
5`;Quand utiliser Tailwind CSS ?
Tailwind CSS est idéal quand :
- Tu veux prototyper rapidement des interfaces
- Tu valorises la cohérence du design (design system dans la config)
- L'équipe aime l'approche utility-first
- Tu te soucies d'un petit bundle (purge des classes inutilisées)
- Tu utilises Next.js ou Vite (excellente intégration)
1// Tailwind -- prototypage rapide
2function Card({ title }) {
3 return (
4 <div className="bg-slate-900 p-6 rounded-xl border border-indigo-700">
5 <h2 className="text-xl font-bold text-purple-400">{title}</h2>
6 </div>
7 );
8}Mélanger les approches
En pratique, de nombreux projets combinent différentes approches :
- Tailwind pour la disposition et le prototypage rapide
- CSS Modules pour les animations complexes et les composants spécifiques
- Styled-components pour les composants avec des styles dynamiques
C'est parfaitement acceptable ! Le plus important est d'établir des conventions au sein de l'équipe et de s'y tenir.
Popularité et tendances
D'après les sondages auprès des développeurs React :
- Tailwind CSS -- popularité croissante, dominant dans les nouveaux projets
- CSS Modules -- popularité stable, souvent utilisé dans Next.js
- Styled-components -- toujours populaire, mais légèrement en déclin
- CSS-in-JS zero-runtime (vanilla-extract, Panda CSS) -- nouvelle tendance, intérêt croissant
Conseils pratiques pour choisir
Avant de choisir une approche de stylage, pose-toi quelques questions :
- Quelle est la taille de l'équipe ? -- une grande équipe peut préférer Tailwind (valeurs cohérentes) ou les CSS Modules (CSS familier)
- As-tu besoin de styles dynamiques ? -- si oui, styled-components ou Emotion seront le meilleur choix
- Quelle est l'importance de la performance ? -- pour les applications où le temps est critique, envisage les CSS Modules ou le CSS-in-JS zero-runtime
- Utilises-tu le SSR ? -- les CSS Modules et Tailwind fonctionnent sans accroc, styled-components nécessitent une configuration supplémentaire
- As-tu du CSS existant ? -- si oui, les CSS Modules offrent la migration la plus facile
Il n'y a pas de solution unique « meilleure » -- chaque approche est un vaisseau spatial différent, conçu pour un type de mission différent. Le plus important est de comprendre les compromis et de choisir ce qui convient le mieux à ton projet et à ton équipe.
Code de cette leçon : App.jsx
1import React, { useState } from 'react';
2import styled from 'styled-components';
3
4const Container = styled.div`
5 font-family: 'Segoe UI', sans-serif;
6 padding: 20px;
7 background: #0a0a2e;
8 color: #e0e0e0;
9 min-height: 100vh;
10`;
11
12const Heading = styled.h1`
13 color: #64b5f6;
14 text-align: center;
15 margin-bottom: 24px;
16`;
17
18const ComparisonGrid = styled.div`
19 display: grid;
20 grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
21 gap: 16px;
22 margin-bottom: 24px;
23`;
24
25const ApproachCard = styled.div`
26 background: ${props => props.active ? '#1a1a5e' : '#1a1a4e'};
27 border: 2px solid ${props => props.active ? '#7c4dff' : '#3949ab'};
28 border-radius: 12px;
29 padding: 20px;
30 cursor: pointer;
31 transition: all 0.3s ease;
32 &:hover { border-color: #7c4dff; transform: translateY(-2px); }
33`;
34
35const ApproachName = styled.h3`
36 color: #7c4dff;
37 margin-bottom: 8px;
38 font-size: 18px;
39`;
40
41const ProsList = styled.ul`
42 list-style: none;
43 padding: 0;
44 margin: 8px 0;
45 li {
46 padding: 4px 0;
47 font-size: 14px;
48 &::before { content: '√ '; color: #00e676; }
49 }
50`;
51
52const ConsList = styled.ul`
53 list-style: none;
54 padding: 0;
55 margin: 8px 0;
56 li {
57 padding: 4px 0;
58 font-size: 14px;
59 &::before { content: '× '; color: #f44336; }
60 }
61`;
62
63const Label = styled.span`
64 font-size: 12px;
65 font-weight: bold;
66 color: ${props => props.type === 'pro' ? '#00e676' : '#f44336'};
67 text-transform: uppercase;
68`;
69
70const approaches = [
71 {
72 name: 'CSS Modules',
73 desc: 'Styles isolés avec des classes automatiquement uniques',
74 pros: ['Zéro runtime JS', 'CSS classique', 'Intégré dans CRA/Next.js', 'Migration facile'],
75 cons: ['Styles dynamiques limités', 'Combinaison de classes plus difficile', 'Pas de theming natif'],
76 bestFor: 'Projets simples, migration depuis du CSS, applications Next.js',
77 },
78 {
79 name: 'Styled-components',
80 desc: 'CSS-in-JS avec tagged template literals et props',
81 pros: ['Styles dynamiques (props)', 'ThemeProvider', 'Pseudo-classes complètes', 'Extension de composants'],
82 cons: ['JS à l\'exécution', 'Bundle plus gros', 'Le SSR nécessite une configuration', 'Courbe d\'apprentissage'],
83 bestFor: 'Bibliothèques de composants, UI dynamique, theming',
84 },
85 {
86 name: 'Tailwind CSS',
87 desc: 'Framework utility-first avec des classes directement dans le JSX',
88 pros: ['Prototypage rapide', 'Petit bundle (purge)', 'Design system cohérent', 'Responsivité (préfixes)'],
89 cons: ['classNames plus longs', 'Courbe d\'apprentissage des classes', 'JSX moins lisible', 'Configuration nécessaire'],
90 bestFor: 'Développement rapide, prototypes, projets avec design system',
91 },
92];
93
94export default function App() {
95 const [selected, setSelected] = useState(0);
96 const approach = approaches[selected];
97
98 return (
99 <Container>
100 <Heading>Comparaison des approches de stylage</Heading>
101
102 <ComparisonGrid>
103 {approaches.map((a, i) => (
104 <ApproachCard
105 key={a.name}
106 active={i === selected}
107 onClick={() => setSelected(i)}
108 >
109 <ApproachName>{a.name}</ApproachName>
110 <p style={{ fontSize: '14px', color: '#b0bec5' }}>{a.desc}</p>
111 </ApproachCard>
112 ))}
113 </ComparisonGrid>
114
115 <div style={{ background: '#1a1a4e', borderRadius: '12px', padding: '24px', border: '1px solid #3949ab' }}>
116 <h2 style={{ color: '#7c4dff', marginBottom: '16px' }}>{approach.name}</h2>
117
118 <Label type="pro">Pour</Label>
119 <ProsList>{approach.pros.map(p => <li key={p}>{p}</li>)}</ProsList>
120
121 <Label type="con">Contre</Label>
122 <ConsList>{approach.cons.map(c => <li key={c}>{c}</li>)}</ConsList>
123
124 <div style={{ marginTop: '16px', padding: '12px', background: '#0d1137', borderRadius: '8px' }}>
125 <span style={{ color: '#64b5f6', fontWeight: 'bold' }}>Idéal pour : </span>
126 <span style={{ color: '#e0e0e0' }}>{approach.bestFor}</span>
127 </div>
128 </div>
129 </Container>
130 );
131}Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Quelle approche ne nécessite PAS de JavaScript supplémentaire à l'exécution dans le navigateur ?
2. Quelle approche est la meilleure pour le prototypage rapide d'interfaces ?
Tâches pratiques dans le jeu
- Clique dans l'ordre
Ordonne la syntaxe composes des CSS Modules :
- Tri horizontal
Ordonne la syntaxe pour combiner des classes CSS Modules avec une condition à l'aide d'un template literal :
- Éditeur de code
Implémente un sélecteur pour trois thèmes spatiaux