Cours JavaScript et React · Module 7: Styles et animations
Sass (SCSS) - Le super-pouvoir syntaxique cosmique
Dans cette leçon9
Dans le cosmos du style React, Sass (Syntactically Awesome Style Sheets) est comme un vaisseau de nouvelle génération : il offre toutes les capacités du CSS standard, mais avec des pouvoirs supplémentaires qui rendent le style plus efficace, plus modulaire et plus facile à maintenir. En naviguant dans la galaxie React, il vaut la peine de maîtriser cette technologie qui peut considérablement simplifier la création de styles avancés.
Qu'est-ce que Sass/SCSS ?
Sass est un préprocesseur CSS qui étend le CSS standard avec des variables, des règles imbriquées, des mixins, l'héritage de sélecteurs et de nombreuses autres fonctionnalités. Il existe deux syntaxes Sass :
- Syntaxe indentée (.sass) - basée sur l'indentation, sans accolades ni points-virgules
- SCSS (.scss) - syntaxe plus récente qui est un sur-ensemble du CSS (tout CSS valide est un SCSS valide)
Dans ce module, nous nous concentrerons sur SCSS, car il est plus populaire et plus facile à apprendre pour les personnes qui connaissent le CSS. Imagine SCSS comme un carburant de fusée amélioré qui conserve toutes les propriétés du carburant standard mais ajoute plus de puissance.
Mettre en place Sass dans un projet React
Pour utiliser Sass dans un projet React, nous devons d'abord installer les paquets appropriés :
Create React App
Si tu utilises Create React App, l'installation est simple :
1npm install sassC'est tout ! CRA prend en charge Sass nativement, donc après l'installation tu peux simplement créer des fichiers .scss/.sass et les importer dans tes composants.
Vite
Dans les projets Vite, le processus est similaire :
1npm install sassVite prend en charge Sass nativement, donc aucune configuration supplémentaire n'est nécessaire.
Autres configurations (par exemple, Webpack personnalisé)
Si tu crées ta propre configuration, tu as besoin de :
1npm install sass sass-loaderEt ajouter la configuration appropriée au fichier webpack.config.js :
1// Configuration webpack simplifiée
2module.exports = {
3 //
4 module: {
5 rules: [
6 {
7 test: /\.s[ac]ss$/i,
8 use: [
9 'style-loader',
10 'css-loader',
11 'sass-loader',
12 ],
13 },
14 ],
15 },
16};Utiliser SCSS dans un projet React
Une fois configuré, tu peux créer des fichiers SCSS et les importer dans tes composants :
1// SpacePanel.jsx
2import React from 'react';
3import './SpacePanel.scss'; // On importe le SCSS au lieu du CSS
4
5function SpacePanel() {
6 return (
7 <div className="space-panel">
8 <h2 className="panel-title">Ship Control Panel</h2>
9 <div className="control-area">
10 <div className="button-group">
11 <button className="control-button primary">Start engines</button>
12 <button className="control-button secondary">Navigation</button>
13 </div>
14 <div className="status-display">Status: Ready for launch</div>
15 </div>
16 </div>
17 );
18}
19
20export default SpacePanel;Fonctionnalités clés de SCSS
1. Les variables
Dans une interface cosmique, nous utilisons souvent les mêmes couleurs, marges ou polices. Les variables SCSS nous permettent de les définir une fois et de les réutiliser autant de fois que nécessaire :
1// variables.scss
2$primary-color: #8a2be2; // Violet cosmique
3$secondary-color: #4a90e2; // Bleu spatial
4$danger-color: #ff4d4f; // Alerte rouge
5$success-color: #52c41a; // Vert « go »
6
7$border-radius-small: 4px;
8$border-radius-medium: 8px;
9$border-radius-large: 16px;
10
11$font-main: 'Space Grotesk', sans-serif;
12$font-display: 'Nova Mono', monospace;
13
14// Utilisation des variables
15.control-button {
16 background-color: $secondary-color;
17 border-radius: $border-radius-medium;
18 font-family: $font-main;
19
20 &.primary {
21 background-color: $primary-color;
22 }
23
24 &.danger {
25 background-color: $danger-color;
26 }
27}2. L'imbrication des sélecteurs
L'imbrication des sélecteurs permet de créer une hiérarchie plus lisible qui reflète la structure HTML :
1.space-panel {
2 background-color: #1a1a2e;
3 padding: 20px;
4 border-radius: 10px;
5
6 .panel-title {
7 color: white;
8 font-size: 24px;
9 margin-bottom: 15px;
10 }
11
12 .control-area {
13 display: flex;
14 justify-content: space-between;
15
16 .button-group {
17 display: flex;
18 gap: 10px;
19
20 .control-button {
21 padding: 10px 15px;
22 // Autres styles de bouton...
23 }
24 }
25
26 .status-display {
27 background-color: rgba(0, 0, 0, 0.3);
28 padding: 10px;
29 border-radius: 5px;
30 }
31 }
32}Cette notation est non seulement plus lisible, mais elle aide aussi à éviter la duplication de sélecteurs et rend la structure plus évidente.
3. Le sélecteur & (esperluette)
L'esperluette (&) représente le sélecteur courant et est particulièrement utile pour :
Pseudo-classes et pseudo-éléments
1.control-button {
2 background-color: #4a90e2;
3 transition: all 0.3s;
4
5 &:hover {
6 background-color: darken(#4a90e2, 10%);
7 transform: translateY(-2px);
8 }
9
10 &:active {
11 transform: translateY(1px);
12 }
13
14 &::before {
15 content: "▲";
16 margin-right: 5px;
17 }
18}Modificateurs de classe
1.control-button {
2 // Styles de base...
3
4 &.primary {
5 background-color: #8a2be2;
6 }
7
8 &.secondary {
9 background-color: #4a90e2;
10 }
11
12 &.large {
13 padding: 12px 20px;
14 font-size: 18px;
15 }
16}Combiner les sélecteurs
1.space-theme {
2 .control-button {
3 // Styles pour .space-theme .control-button
4 }
5
6 // Avec & on peut sélectionner différentes combinaisons de sélecteurs
7 &__dark .control-button {
8 // Styles pour .space-theme__dark .control-button
9 }
10}4. Les mixins - Code réutilisable
Les mixins sont des ensembles de déclarations CSS qui peuvent être utilisés plusieurs fois dans le code. Ce sont comme des modules de vaisseau réutilisables :
1// mixins.scss
2@mixin flex-center {
3 display: flex;
4 justify-content: center;
5 align-items: center;
6}
7
8@mixin glass-effect {
9 background: rgba(255, 255, 255, 0.1);
10 backdrop-filter: blur(10px);
11 border: 1px solid rgba(255, 255, 255, 0.2);
12 box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2);
13}
14
15@mixin button-variant($bg-color, $text-color) {
16 background-color: $bg-color;
17 color: $text-color;
18
19 &:hover {
20 background-color: darken($bg-color, 10%);
21 }
22
23 &:active {
24 background-color: darken($bg-color, 15%);
25 }
26}Utilisation des mixins :
1.control-panel {
2 @include glass-effect;
3 padding: 20px;
4}
5
6.button-container {
7 @include flex-center;
8 gap: 10px;
9}
10
11.launch-button {
12 @include button-variant(#ff4d4f, white);
13 padding: 10px 20px;
14}
15
16.navigation-button {
17 @include button-variant(#4a90e2, white);
18 padding: 8px 15px;
19}5. L'héritage - @extend
L'héritage permet à une classe d'hériter des propriétés d'une autre, réduisant ainsi la duplication de code :
1.base-button {
2 padding: 10px 15px;
3 border: none;
4 border-radius: 4px;
5 font-weight: bold;
6 cursor: pointer;
7 transition: all 0.3s;
8}
9
10.primary-button {
11 @extend .base-button;
12 background-color: #8a2be2;
13 color: white;
14}
15
16.secondary-button {
17 @extend .base-button;
18 background-color: #4a90e2;
19 color: white;
20}
21
22.ghost-button {
23 @extend .base-button;
24 background-color: transparent;
25 color: #8a2be2;
26 border: 1px solid currentColor;
27}6. Fonctions mathématiques et de couleur
SCSS offre de nombreuses fonctions intégrées pour manipuler les couleurs et les valeurs :
1.panel {
2 // Opérations mathématiques
3 width: 100% - 40px;
4 padding: 10px * 2;
5
6 // Fonctions de couleur
7 background-color: lighten(#1a1a2e, 10%);
8 border: 1px solid darken(#1a1a2e, 5%);
9
10 .warning-label {
11 color: transparentize(#ff4d4f, 0.2); // Ajoute de la transparence
12 }
13
14 .accent-element {
15 background-color: mix(#8a2be2, #4a90e2, 30%); // Mélange les couleurs
16 }
17}7. Import et organisation des fichiers
SCSS permet de découper le code en fichiers modulaires, ce qui est crucial pour les grands projets :
1// styles/variables.scss
2$primary-color: #8a2be2;
3// Autres variables...
4
5// styles/mixins.scss
6@mixin flex-center { /* ... */ }
7// Autres mixins...
8
9// styles/buttons.scss
10@import 'variables';
11@import 'mixins';
12
13.button { /* ... */ }
14// Styles de bouton...
15
16// styles/panels.scss
17@import 'variables';
18@import 'mixins';
19
20.panel { /* ... */ }
21// Styles de panneau...
22
23// styles/main.scss
24@import 'variables';
25@import 'mixins';
26@import 'buttons';
27@import 'panels';
28// On peut tout importer ensemble ou de façon sélective dans les composants8. Opérateurs conditionnels et boucles
SCSS propose aussi des structures de contrôle connues des langages de programmation :
1// Conditions
2$theme: 'dark';
3
4.space-control {
5 @if $theme == 'dark' {
6 background-color: #121212;
7 color: white;
8 } @else {
9 background-color: #f5f5f5;
10 color: #333;
11 }
12}
13
14// Boucles
15$sizes: (
16 'small': 8px,
17 'medium': 16px,
18 'large': 24px,
19 'xlarge': 32px
20);
21
22@each $name, $size in $sizes {
23 .margin-#{$name} {
24 margin: $size;
25 }
26
27 .padding-#{$name} {
28 padding: $size;
29 }
30}
31
32// Génère :
33// .margin-small { margin: 8px; }
34// .padding-small { padding: 8px; }
35// ...etc. pour toutes les taillesIntégrer SCSS avec les CSS Modules dans React
SCSS peut se combiner parfaitement avec les CSS Modules, créant une solution de style puissante :
1// SpacePanel.module.scss
2@import 'src/styles/variables';
3@import 'src/styles/mixins';
4
5.panel {
6 @include glass-effect;
7 background-color: $panel-bg-color;
8
9 .title {
10 color: $text-primary;
11 font-family: $font-display;
12 }
13
14 .controls {
15 display: flex;
16 gap: $spacing-md;
17
18 .button {
19 @include button-base;
20
21 &.primary {
22 @include button-variant($primary-color, white);
23 }
24
25 &.secondary {
26 @include button-variant($secondary-color, white);
27 }
28 }
29 }
30}Utilisation dans un composant :
1import React from 'react';
2import styles from './SpacePanel.module.scss';
3
4function SpacePanel() {
5 return (
6 <div className={styles.panel}>
7 <h2 className={styles.title}>Control Panel</h2>
8 <div className={styles.controls}>
9 <button className={`${styles.button} ${styles.primary}`}>
10 Launch
11 </button>
12 <button className={`${styles.button} ${styles.secondary}`}>
13 Cancel
14 </button>
15 </div>
16 </div>
17 );
18}Bonnes pratiques pour utiliser SCSS dans React
1. Structure des fichiers
Organise tes fichiers SCSS d'une façon qui reflète la structure des composants :
1src/
2├── styles/ # Global styles and assets
3│ ├── _variables.scss # Convention : les fichiers avec underscore sont réservés à l'import
4│ ├── _mixins.scss
5│ ├── _functions.scss
6│ ├── _reset.scss
7│ └── global.scss # Fichier principal des styles globaux
8├── components/
9│ ├── Button/
10│ │ ├── Button.jsx
11│ │ └── Button.module.scss
12│ ├── Panel/
13│ │ ├── Panel.jsx
14│ │ └── Panel.module.scss
15│ └──
16└──2. Conventions de nommage
Utilise des conventions de nommage cohérentes :
- BEM (Block, Element, Modifier) - pour les classes CSS
- camelCase - pour les variables et mixins SCSS
- PascalCase - pour les composants React
- kebab-case - pour les fichiers SCSS
1// _variables.scss
2$primaryColor: #8a2be2;
3$secondaryColor: #4a90e2;
4
5// Button.module.scss (using BEM)
6.button {
7 // Bloc
8 background-color: $primaryColor;
9
10 &__icon {
11 // Élément
12 margin-right: 8px;
13 }
14
15 &--large {
16 // Modificateur
17 padding: 12px 24px;
18 }
19}3. Évite l'imbrication excessive
Une imbrication trop profonde peut conduire à des sélecteurs trop spécifiques, plus difficiles à surcharger :
1// À éviter :
2.panel {
3 .content {
4 .section {
5 .title {
6 .icon {
7 // 5 niveaux d'imbrication !
8 color: red;
9 }
10 }
11 }
12 }
13}
14
15// Mieux :
16.panel {
17 // Styles généraux du panneau
18}
19
20.panel-content {
21 // Styles du contenu
22}
23
24.section-title-icon {
25 color: red;
26}4. Utilise des variables pour les valeurs répétées
1// _spacing.scss
2$spacing-xs: 4px;
3$spacing-sm: 8px;
4$spacing-md: 16px;
5$spacing-lg: 24px;
6$spacing-xl: 32px;
7
8// _colors.scss
9$blue-100: #e3f2fd;
10$blue-200: #bbdefb;
11//
12$blue-900: #0d47a1;
13
14$color-primary: $blue-500;
15$color-secondary: $purple-500;5. Crée des mixins systèmes
1@mixin media-breakpoint-up($breakpoint) {
2 @if $breakpoint == sm {
3 @media (min-width: 576px) { @content; }
4 } @else if $breakpoint == md {
5 @media (min-width: 768px) { @content; }
6 } @else if $breakpoint == lg {
7 @media (min-width: 992px) { @content; }
8 } @else if $breakpoint == xl {
9 @media (min-width: 1200px) { @content; }
10 }
11}
12
13// Utilisation :
14.responsive-element {
15 font-size: 14px;
16
17 @include media-breakpoint-up(md) {
18 font-size: 16px;
19 }
20
21 @include media-breakpoint-up(lg) {
22 font-size: 18px;
23 }
24}Exemple pratique : Panneau de contrôle de vaisseau
Voyons comment appliquer SCSS pour créer un panneau de contrôle interactif :
1// _variables.scss
2$primary-color: #7b2cbf;
3$secondary-color: #3a86ff;
4$success-color: #06d6a0;
5$warning-color: #ffd166;
6$danger-color: #ef476f;
7$dark-bg: #1a1a2e;
8$panel-bg: #252941;
9$text-light: #e6e6ff;
10
11$border-radius-sm: 4px;
12$border-radius-md: 8px;
13$border-radius-lg: 12px;
14
15$transition-fast: 0.2s ease;
16$transition-normal: 0.3s ease;
17
18// _mixins.scss
19@mixin glass-morphism {
20 background: rgba(37, 41, 65, 0.8);
21 backdrop-filter: blur(10px);
22 border: 1px solid rgba(255, 255, 255, 0.1);
23 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
24}
25
26@mixin button-glow($color) {
27 box-shadow: 0 0 15px rgba($color, 0.5);
28 &:hover {
29 box-shadow: 0 0 25px rgba($color, 0.7);
30 }
31}
32
33// SpaceControlPanel.module.scss
34@import 'src/styles/variables';
35@import 'src/styles/mixins';
36
37.controlPanel {
38 @include glass-morphism;
39 padding: 24px;
40 border-radius: $border-radius-lg;
41 color: $text-light;
42
43 .panelHeader {
44 display: flex;
45 justify-content: space-between;
46 align-items: center;
47 margin-bottom: 24px;
48 padding-bottom: 16px;
49 border-bottom: 1px solid rgba(255, 255, 255, 0.1);
50
51 .title {
52 font-size: 28px;
53 font-weight: 600;
54
55 &::before {
56 content: "▲";
57 margin-right: 10px;
58 }
59 }
60
61 .status {
62 padding: 6px 12px;
63 border-radius: $border-radius-sm;
64 font-size: 14px;
65 font-weight: 500;
66
67 &.ready {
68 background-color: rgba($success-color, 0.2);
69 color: $success-color;
70 }
71
72 &.standby {
73 background-color: rgba($warning-color, 0.2);
74 color: $warning-color;
75 }
76
77 &.error {
78 background-color: rgba($danger-color, 0.2);
79 color: $danger-color;
80 }
81 }
82 }
83
84 .controlGrid {
85 display: grid;
86 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
87 gap: 20px;
88
89 .controlSection {
90 background-color: rgba(0, 0, 0, 0.2);
91 border-radius: $border-radius-md;
92 padding: 16px;
93
94 .sectionTitle {
95 font-size: 18px;
96 margin-bottom: 16px;
97 color: rgba($text-light, 0.8);
98 }
99
100 .buttonGroup {
101 display: flex;
102 flex-direction: column;
103 gap: 12px;
104 }
105 }
106 }
107
108 .button {
109 padding: 12px 16px;
110 border: none;
111 border-radius: $border-radius-sm;
112 font-weight: 500;
113 letter-spacing: 0.5px;
114 cursor: pointer;
115 transition: all $transition-normal;
116 position: relative;
117 overflow: hidden;
118
119 &::before {
120 content: "";
121 position: absolute;
122 top: 0;
123 left: -100%;
124 width: 100%;
125 height: 100%;
126 background: linear-gradient(
127 90deg,
128 transparent,
129 rgba(255, 255, 255, 0.2),
130 transparent
131 );
132 transition: all 0.6s;
133 }
134
135 &:hover::before {
136 left: 100%;
137 }
138
139 &.primary {
140 background-color: $primary-color;
141 color: white;
142 @include button-glow($primary-color);
143 }
144
145 &.secondary {
146 background-color: $secondary-color;
147 color: white;
148 @include button-glow($secondary-color);
149 }
150
151 &.success {
152 background-color: $success-color;
153 color: black;
154 @include button-glow($success-color);
155 }
156
157 &.warning {
158 background-color: $warning-color;
159 color: black;
160 @include button-glow($warning-color);
161 }
162
163 &.danger {
164 background-color: $danger-color;
165 color: white;
166 @include button-glow($danger-color);
167 }
168
169 &.disabled {
170 opacity: 0.5;
171 cursor: not-allowed;
172 pointer-events: none;
173 }
174 }
175
176 .monitorDisplay {
177 margin-top: 24px;
178 padding: 16px;
179 background-color: rgba(0, 0, 0, 0.4);
180 border-radius: $border-radius-md;
181 font-family: monospace;
182 height: 120px;
183 overflow-y: auto;
184
185 .logLine {
186 margin: 4px 0;
187 font-size: 14px;
188
189 &.info {
190 color: $secondary-color;
191 }
192
193 &.success {
194 color: $success-color;
195 }
196
197 &.warning {
198 color: $warning-color;
199 }
200
201 &.error {
202 color: $danger-color;
203 }
204
205 &::before {
206 content: "> ";
207 }
208 }
209 }
210}
211
212// Utilisation dans un composant React
213import React, { useState } from 'react';
214import styles from './SpaceControlPanel.module.scss';
215
216function SpaceControlPanel() {
217 const [status, setStatus] = useState('standby');
218 const [logs, setLogs] = useState([
219 { type: 'info', text: 'System initialized' },
220 { type: 'info', text: 'Waiting for commands' }
221 ]);
222
223 const addLog = (text, type = 'info') => {
224 setLogs(prev => [...prev, { type, text }]);
225 };
226
227 const initiateSequence = () => {
228 setStatus('ready');
229 addLog('Launch sequence initiated', 'success');
230 };
231
232 const abortSequence = () => {
233 setStatus('standby');
234 addLog('Launch sequence aborted', 'warning');
235 };
236
237 const triggerAlert = () => {
238 setStatus('error');
239 addLog('ALERT: Critical system failure detected', 'error');
240 };
241
242 return (
243 <div className={styles.controlPanel}>
244 <div className={styles.panelHeader}>
245 <h2 className={styles.title}>Cosmic Control Panel</h2>
246 <div className={`${styles.status} ${styles[status]}`}>
247 Status: {status === 'standby' ? 'Standby' :
248 status === 'ready' ? 'Ready' : 'Error'}
249 </div>
250 </div>
251
252 <div className={styles.controlGrid}>
253 <div className={styles.controlSection}>
254 <h3 className={styles.sectionTitle}>Launch Control</h3>
255 <div className={styles.buttonGroup}>
256 <button
257 className={`${styles.button} ${styles.success}`}
258 onClick={initiateSequence}
259 >
260 Initiate Launch
261 </button>
262 <button
263 className={`${styles.button} ${styles.warning}`}
264 onClick={abortSequence}
265 >
266 Abort Sequence
267 </button>
268 </div>
269 </div>
270
271 <div className={styles.controlSection}>
272 <h3 className={styles.sectionTitle}>Onboard Systems</h3>
273 <div className={styles.buttonGroup}>
274 <button
275 className={`${styles.button} ${styles.primary}`}
276 onClick={() => addLog('Navigation systems online', 'info')}
277 >
278 Navigation System
279 </button>
280 <button
281 className={`${styles.button} ${styles.secondary}`}
282 onClick={() => addLog('Life support activated', 'info')}
283 >
284 Life Support
285 </button>
286 </div>
287 </div>
288
289 <div className={styles.controlSection}>
290 <h3 className={styles.sectionTitle}>Safety</h3>
291 <div className={styles.buttonGroup}>
292 <button
293 className={`${styles.button} ${styles.danger}`}
294 onClick={triggerAlert}
295 >
296 Emergency Alert
297 </button>
298 <button
299 className={`${styles.button} ${styles.disabled}`}
300 >
301 Evacuation Protocol
302 </button>
303 </div>
304 </div>
305 </div>
306
307 <div className={styles.monitorDisplay}>
308 {logs.map((log, index) => (
309 <div key={index} className={`${styles.logLine} ${styles[log.type]}`}>
310 {log.text}
311 </div>
312 ))}
313 </div>
314 </div>
315 );
316}
317
318export default SpaceControlPanel;Sass vs CSS-in-JS : lequel utiliser ?
Avantages de SCSS
- Performance - le CSS est généré au moment du build, pas à l'exécution
- Syntaxe familière - très proche du CSS standard
- Support des outils - prise en charge complète des outils de développement (DevTools)
- Extraction du CSS - les styles peuvent être extraits dans des fichiers CSS séparés
- Taille de bundle réduite - ne nécessite pas de bibliothèques JS supplémentaires
Quand choisir SCSS ?
- Dans les grands projets aux styles complexes
- Quand tu préfères séparer la logique et le style
- Quand la performance est critique
- Quand tu travailles avec des designers qui utilisent du CSS/SCSS traditionnel
- Quand l'équipe a de l'expérience avec SCSS
Résumé
Sass (SCSS) est un outil puissant qui étend considérablement les capacités du CSS tout en restant proche de sa syntaxe d'origine. Dans l'écosystème React, SCSS s'intègre bien à la fois avec l'approche modulaire (CSS Modules) et avec d'autres techniques de style.
Grâce aux variables, aux mixins, à l'imbrication et à d'autres fonctionnalités, SCSS permet de créer un code CSS plus modulaire et plus facile à maintenir, ce qui est particulièrement important dans les grandes applications React.
Comme tout vaisseau avancé, SCSS demande un peu de temps à maîtriser, mais l'investissement dans l'apprentissage est vite rentabilisé sous la forme d'un travail plus efficace et d'un code mieux organisé. Pour les applications React, où la gestion des composants et de leurs styles est cruciale, SCSS est l'une des meilleures options de style, offrant un excellent équilibre entre puissance et simplicité.
Code de cette leçon : App.jsx
1import React, { useState } from 'react';
2import styled, { ThemeProvider, createGlobalStyle, keyframes } from 'styled-components';
3
4// Définition des thèmes
5const themes = {
6 space: {
7 primary: '#00d4ff',
8 secondary: '#ffd700',
9 background: 'linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%)',
10 cardBg: 'rgba(255, 255, 255, 0.05)',
11 text: '#ffffff',
12 textSecondary: '#a0a0a0',
13 },
14 nebula: {
15 primary: '#ff6b9d',
16 secondary: '#c44569',
17 background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
18 cardBg: 'rgba(255, 107, 157, 0.1)',
19 text: '#ffffff',
20 textSecondary: '#b0b0b0',
21 },
22 solar: {
23 primary: '#ffa502',
24 secondary: '#ff6348',
25 background: 'linear-gradient(135deg, #2c2c54 0%, #474787 50%, #706fd3 100%)',
26 cardBg: 'rgba(255, 165, 2, 0.1)',
27 text: '#ffffff',
28 textSecondary: '#c0c0c0',
29 },
30};
31
32// Global styles
33const GlobalStyle = createGlobalStyle`
34 * {
35 margin: 0;
36 padding: 0;
37 box-sizing: border-box;
38 }
39
40 body {
41 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
42 min-height: 100vh;
43 }
44`;
45
46// Animations
47const float = keyframes`
48 0%, 100% { transform: translateY(0); }
49 50% { transform: translateY(-10px); }
50`;
51
52const pulse = keyframes`
53 0%, 100% { opacity: 1; }
54 50% { opacity: 0.7; }
55`;
56
57// Styled components
58const AppContainer = styled.div`
59 min-height: 100vh;
60 background: ${props => props.theme.background};
61 padding: 30px;
62 color: ${props => props.theme.text};
63 transition: all 0.5s ease;
64`;
65
66const Header = styled.header`
67 text-align: center;
68 margin-bottom: 40px;
69`;
70
71const Title = styled.h1`
72 font-size: 2.5em;
73 color: ${props => props.theme.primary};
74 text-shadow: 0 0 20px ${props => props.theme.primary}40;
75 animation: ${float} 3s ease-in-out infinite;
76`;
77
78const Subtitle = styled.p`
79 color: ${props => props.theme.textSecondary};
80 margin-top: 10px;
81`;
82
83const ThemeSelector = styled.div`
84 display: flex;
85 justify-content: center;
86 gap: 15px;
87 margin-bottom: 40px;
88`;
89
90const ThemeButton = styled.button`
91 padding: 12px 24px;
92 border: 2px solid ${props => props.active ? props.theme.primary : 'transparent'};
93 border-radius: 8px;
94 background: ${props => props.theme.cardBg};
95 color: ${props => props.theme.text};
96 cursor: pointer;
97 font-weight: bold;
98 transition: all 0.3s ease;
99
100 &:hover {
101 background: ${props => props.theme.primary}30;
102 transform: translateY(-2px);
103 }
104`;
105
106const CardsGrid = styled.div`
107 display: grid;
108 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
109 gap: 25px;
110 max-width: 1200px;
111 margin: 0 auto;
112`;
113
114const Card = styled.div`
115 background: ${props => props.theme.cardBg};
116 border-radius: 15px;
117 padding: 25px;
118 border: 1px solid ${props => props.theme.primary}30;
119 transition: all 0.3s ease;
120
121 &:hover {
122 transform: translateY(-5px);
123 box-shadow: 0 10px 30px ${props => props.theme.primary}20;
124 }
125`;
126
127const CardTitle = styled.h3`
128 color: ${props => props.theme.secondary};
129 margin-bottom: 15px;
130 font-size: 1.4em;
131`;
132
133const CardText = styled.p`
134 color: ${props => props.theme.textSecondary};
135 line-height: 1.6;
136 margin-bottom: 20px;
137`;
138
139const Button = styled.button`
140 padding: 10px 20px;
141 background: ${props => props.variant === 'primary'
142 ? props.theme.primary
143 : 'transparent'};
144 color: ${props => props.variant === 'primary'
145 ? '#000'
146 : props.theme.primary};
147 border: 2px solid ${props => props.theme.primary};
148 border-radius: 6px;
149 cursor: pointer;
150 font-weight: bold;
151 transition: all 0.3s ease;
152
153 &:hover {
154 background: ${props => props.theme.primary};
155 color: #000;
156 transform: scale(1.05);
157 }
158
159 &:disabled {
160 opacity: 0.5;
161 cursor: not-allowed;
162 }
163`;
164
165const StatusBadge = styled.span`
166 display: inline-block;
167 padding: 4px 12px;
168 border-radius: 20px;
169 font-size: 0.85em;
170 font-weight: bold;
171 background: ${props => {
172 switch(props.status) {
173 case 'active': return 'rgba(76, 175, 80, 0.2)';
174 case 'pending': return 'rgba(255, 152, 0, 0.2)';
175 case 'inactive': return 'rgba(244, 67, 54, 0.2)';
176 default: return 'rgba(255, 255, 255, 0.1)';
177 }
178 }};
179 color: ${props => {
180 switch(props.status) {
181 case 'active': return '#4CAF50';
182 case 'pending': return '#ff9800';
183 case 'inactive': return '#f44336';
184 default: return '#fff';
185 }
186 }};
187 animation: ${props => props.status === 'active' ? pulse : 'none'} 2s infinite;
188`;
189
190const Footer = styled.footer`
191 text-align: center;
192 margin-top: 50px;
193 color: ${props => props.theme.textSecondary};
194 padding: 20px;
195 border-top: 1px solid ${props => props.theme.primary}20;
196`;
197
198// Composants de données
199const missions = [
200 {
201 id: 1,
202 name: 'Exploration de Mars',
203 description: 'Mission de recherche à la surface de la planète rouge',
204 status: 'active',
205 },
206 {
207 id: 2,
208 name: 'Station orbitale',
209 description: "Construction d'une nouvelle station spatiale en orbite terrestre",
210 status: 'pending',
211 },
212 {
213 id: 3,
214 name: 'Sonde jovienne',
215 description: "Étude de l'atmosphère de la plus grande planète du système solaire",
216 status: 'inactive',
217 },
218];
219
220function App() {
221 const [currentTheme, setCurrentTheme] = useState('space');
222
223 return (
224 <ThemeProvider theme={themes[currentTheme]}>
225 <GlobalStyle />
226 <AppContainer>
227 <Header>
228 <Title>Styled Components Demo</Title>
229 <Subtitle>Stylisation dynamique avec thèmes dans React</Subtitle>
230 </Header>
231
232 <ThemeSelector>
233 {Object.keys(themes).map(themeName => (
234 <ThemeButton
235 key={themeName}
236 active={currentTheme === themeName}
237 onClick={() => setCurrentTheme(themeName)}
238 >
239 {themeName.charAt(0).toUpperCase() + themeName.slice(1)}
240 </ThemeButton>
241 ))}
242 </ThemeSelector>
243
244 <CardsGrid>
245 {missions.map(mission => (
246 <Card key={mission.id}>
247 <CardTitle>{mission.name}</CardTitle>
248 <StatusBadge status={mission.status}>
249 {mission.status}
250 </StatusBadge>
251 <CardText>{mission.description}</CardText>
252 <Button variant="primary">Détails</Button>
253 </Card>
254 ))}
255 </CardsGrid>
256
257 <Footer>
258 <p>Styled-components permet d'écrire du CSS en JavaScript</p>
259 <p>avec une prise en charge complète des thèmes et des styles dynamiques</p>
260 </Footer>
261 </AppContainer>
262 </ThemeProvider>
263 );
264}
265
266export default App;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 syntaxe SCSS est compatible avec le CSS ?
2. Que signifie l'opérateur & dans les sélecteurs SCSS imbriqués ?
Voici 2 des 5 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Tri horizontal
Ordonne la commande d'installation de SCSS dans un projet React :
- Clique dans l'ordre
Ordonne la définition d'une variable SCSS :
- Éditeur de code
Système de variables SCSS
- Éditeur de code
Imbrication SCSS et l'opérateur &
- Clique dans l'ordre
Ordonne la définition d'un mixin en SCSS :
- Tri vertical
Ordonne les étapes pour ajouter SCSS à un projet React :
- Tri vertical
Ordonne les éléments de la directive @extend en SCSS, de gauche à droite :
- Éditeur de code
Mixins SCSS pour les composants
- Tri vertical
Ordonne un sélecteur SCSS imbriqué avec la pseudo-classe hover :
- Éditeur de code
Fonctions SCSS
- Clique dans l'ordre
Ordonne la syntaxe BEM en SCSS, du bloc au modificateur :
- Tri vertical
Classe les étapes de la compilation SCSS :
- Éditeur de code
CSS Modules avec SCSS