Cours Next.js · Module 3: Styles et optimisation visuelle
Styles globaux et CSS Modules dans Next.js 16
Dans cette leçon9
Bienvenue à Quantum Metropolis, la ville du futur, où chaque élément de l'espace urbain possède son propre style unique, tout en maintenant une esthétique d'ensemble cohérente. Comme dans cette ville futuriste, dans les applications Next.js 16 nous avons besoin à la fois de règles de style globales qui définissent l'apparence générale, et de styles locaux et modulaires qui évitent les conflits et maintiennent l'ordre.
Dans ce chapitre, nous allons explorer deux approches clés du style dans Next.js 16 :
- Les styles globaux - qui affectent toute l'application
- Les CSS Modules - qui permettent un style de composant local et encapsulé
Les styles globaux dans Next.js 16
À Quantum Metropolis, les éléments d'infrastructure fondamentaux comme le système de transport, l'éclairage et la signalétique ont une apparence uniforme dans toute la ville. De même, dans les applications web, nous avons besoin de règles de style globales pour les éléments de base comme la typographie, les couleurs, les marges et les grilles.
Le fichier global.css
Dans Next.js 16, les styles globaux sont le plus souvent définis dans le fichier app/globals.css, qui est ensuite importé dans le layout principal de l'application. Voici à quoi ressemble une structure typique :
1// app/layout.tsx
2import './globals.css';
3import type { Metadata } from 'next';
4
5export const metadata: Metadata = {
6 title: 'Metropolis Quantum',
7 description: 'Your gateway to the city of the future',
8};
9
10export default function RootLayout({
11 children,
12}: {
13 children: React.ReactNode;
14}) {
15 return (
16 <html lang="pl">
17 <body>{children}</body>
18 </html>
19 );
20}Le contenu du fichier globals.css pourrait ressembler à ceci :
1/* app/globals.css */
2:root {
3 --primary-color: #3a86ff;
4 --secondary-color: #8338ec;
5 --accent-color: #ff006e;
6 --background-light: #f8f9fa;
7 --background-dark: #212529;
8 --text-light: #f8f9fa;
9 --text-dark: #212529;
10 --spacing-unit: 0.5rem;
11 --border-radius: 0.375rem;
12}
13
14* {
15 box-sizing: border-box;
16 padding: 0;
17 margin: 0;
18}
19
20html,
21body {
22 max-width: 100vw;
23 overflow-x: hidden;
24 font-family: 'Quantum Sans', sans-serif;
25}
26
27body {
28 color: var(--text-dark);
29 background: var(--background-light);
30}
31
32a {
33 color: var(--primary-color);
34 text-decoration: none;
35}
36
37h1, h2, h3, h4, h5, h6 {
38 font-family: 'Quantum Display', sans-serif;
39 margin-bottom: var(--spacing-unit);
40}
41
42.container {
43 width: 100%;
44 max-width: 1200px;
45 margin: 0 auto;
46 padding: 0 var(--spacing-unit);
47}
48
49@media (prefers-color-scheme: dark) {
50 body {
51 color: var(--text-light);
52 background: var(--background-dark);
53 }
54}Reset et normalisation CSS
C'est souvent une bonne pratique de commencer par un CSS Reset ou une normalisation, qui élimine les différences entre les styles par défaut des différents navigateurs. Tu peux utiliser des solutions populaires comme :
normalize.cssreset.css- Une solution sur mesure
Par exemple, tu peux installer normalize.css via npm et l'importer au début du fichier globals.css :
1npm install normalize.css1/* app/globals.css */
2@import 'normalize.css';
3
4/* Rest of global styles */Utiliser les variables CSS
Comme tu peux le voir dans l'exemple ci-dessus, les variables CSS (custom properties) sont un outil puissant pour définir des valeurs globales qui peuvent ensuite être utilisées dans toute l'application :
1:root {
2 --primary-color: #3a86ff;
3 --spacing-large: 2rem;
4}
5
6.button {
7 background-color: var(--primary-color);
8 padding: var(--spacing-large);
9}Cette approche permet de gérer facilement les palettes de couleurs, les espacements, les tailles de police et d'autres valeurs récurrentes.
Styles globaux pour des routes spécifiques
Dans Next.js 16, tu peux aussi définir des styles globaux qui ne s'appliqueront qu'à certaines routes ou layouts. Cela se fait via des fichiers layout.tsx dans des répertoires spécifiques :
1// app/dashboard/layout.tsx
2import '../dashboard-styles.css';
3
4export default function DashboardLayout({
5 children,
6}: {
7 children: React.ReactNode;
8}) {
9 return <div className="dashboard-container">{children}</div>;
10}Ces styles ne s'appliqueront qu'aux pages situées dans le répertoire /dashboard.
CSS Modules : l'encapsulation des styles
À Quantum Metropolis, chaque quartier possède sa propre esthétique unique : le Quartier Quantique regorge d'éléments futuristes et holographiques, tandis que la Vieille Ville mêle modernité et architecture rétro. Malgré ces différences, tous les quartiers forment un ensemble cohérent.
Les CSS Modules fonctionnent de manière similaire : ils permettent de créer des styles locaux et encapsulés pour les composants, qui n'affecteront pas le reste de l'application.
Les bases des CSS Modules
Les CSS Modules sont une technique qui crée automatiquement des noms de classe CSS uniques, évitant ainsi les conflits. Dans Next.js 16, tout fichier portant l'extension .module.css est traité comme un module CSS.
Créer et utiliser un module CSS :
1/* Button.module.css */
2.button {
3 padding: 0.75rem 1.5rem;
4 border-radius: 0.375rem;
5 font-weight: 600;
6 transition: all 0.2s;
7}
8
9.primary {
10 background-color: var(--primary-color);
11 color: white;
12}
13
14.secondary {
15 background-color: var(--secondary-color);
16 color: white;
17}
18
19.button:hover {
20 transform: translateY(-2px);
21 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
22}1// components/Button.tsx
2import styles from './Button.module.css';
3
4interface ButtonProps {
5 variant?: 'primary' | 'secondary';
6 children: React.ReactNode;
7 onClick?: () => void;
8}
9
10export default function Button({ variant = 'primary', children, onClick }: ButtonProps) {
11 return (
12 <button
13 className={`${styles.button} ${styles[variant]}`}
14 onClick={onClick}
15 >
16 {children}
17 </button>
18 );
19}Comment fonctionnent les CSS Modules
Lors de la construction de l'application, Next.js traite les fichiers .module.css et génère des noms de classe uniques. Par exemple, la classe .button de l'exemple ci-dessus peut être transformée en .Button_button__XYZ123. Grâce à cela, même si tu définis une classe portant le même nom dans un autre composant, il n'y aura aucun conflit.
Accéder aux variables CSS globales
Les CSS Modules peuvent utiliser les variables CSS globales définies dans globals.css :
1/* Card.module.css */
2.card {
3 background-color: white;
4 border-radius: var(--border-radius);
5 padding: calc(var(--spacing-unit) * 2);
6 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
7}Composer des classes
Les CSS Modules permettent de composer des classes grâce à la syntaxe composes :
1/* Text.module.css */
2.base {
3 font-family: 'Quantum Sans', sans-serif;
4 line-height: 1.5;
5}
6
7.heading {
8 composes: base;
9 font-weight: 700;
10 line-height: 1.2;
11}
12
13.paragraph {
14 composes: base;
15 margin-bottom: 1rem;
16}Styles dynamiques avec les CSS Modules
Tu peux appliquer des classes de façon dynamique selon l'état du composant :
1// components/Alert.tsx
2import { useState } from 'react';
3import styles from './Alert.module.css';
4
5interface AlertProps {
6 type: 'info' | 'success' | 'warning' | 'error';
7 message: string;
8}
9
10export default function Alert({ type, message }: AlertProps) {
11 const [isVisible, setIsVisible] = useState(true);
12
13 if (!isVisible) return null;
14
15 return (
16 <div className={`${styles.alert} ${styles[type]} ${isVisible ? styles.visible : ''}`}>
17 <p>{message}</p>
18 <button
19 className={styles.closeButton}
20 onClick={() => setIsVisible(false)}
21 >
22 ×
23 </button>
24 </div>
25 );
26}1/* Alert.module.css */
2.alert {
3 padding: 1rem;
4 border-radius: var(--border-radius);
5 margin-bottom: 1rem;
6 display: flex;
7 justify-content: space-between;
8 align-items: center;
9}
10
11.info {
12 background-color: #e3f2fd;
13 color: #0d47a1;
14}
15
16.success {
17 background-color: #e8f5e9;
18 color: #1b5e20;
19}
20
21.warning {
22 background-color: #fff3e0;
23 color: #e65100;
24}
25
26.error {
27 background-color: #ffebee;
28 color: #b71c1c;
29}
30
31.visible {
32 opacity: 1;
33 transition: opacity 0.3s ease-in;
34}
35
36.closeButton {
37 background: none;
38 border: none;
39 font-size: 1.5rem;
40 cursor: pointer;
41 opacity: 0.7;
42}
43
44.closeButton:hover {
45 opacity: 1;
46}Combiner styles globaux et CSS Modules
Dans les applications réelles, on utilise le plus souvent les deux approches :
Les styles globaux pour :
- Les resets CSS
- Les éléments typographiques de base
- Les variables (couleurs, espacements, ombres, etc.)
- Les classes utilitaires
Les CSS Modules pour :
- Les composants spécifiques
- Les éléments qui peuvent avoir des styles différents selon le contexte
Exemple : structure de projet
1app/
2├── layout.tsx
3├── page.tsx
4├── globals.css
5├── dashboard/
6│ ├── layout.tsx
7│ ├── page.tsx
8│ └── dashboard.module.css
9└── components/
10 ├── Button/
11 │ ├── Button.tsx
12 │ └── Button.module.css
13 ├── Card/
14 │ ├── Card.tsx
15 │ └── Card.module.css
16 └──Approches de style alternatives dans Next.js 16
Outre les styles globaux et les CSS Modules, Next.js 16 prend également en charge d'autres approches de style :
1. Styled JSX
Next.js prend en charge nativement Styled JSX, qui permet de créer des styles locaux directement dans les composants :
1export default function Button() {
2 return (
3 <>
4 <button>Cliquez-moi</button>
5 <style jsx>{`
6 button {
7 padding: 0.5rem 1rem;
8 background-color: #3a86ff;
9 color: white;
10 border: none;
11 border-radius: 0.25rem;
12 }
13 button:hover {
14 background-color: #2563eb;
15 }
16 `}</style>
17 </>
18 );
19}2. Sass/SCSS
Next.js prend aussi en charge Sass/SCSS. Il suffit d'installer sass :
1npm install sassTu peux ensuite créer des fichiers .scss ou .sass, y compris des modules CSS avec l'extension .module.scss :
1// Button.module.scss
2$primary-color: #3a86ff;
3
4.button {
5 padding: 0.75rem 1.5rem;
6 background-color: $primary-color;
7
8 &:hover {
9 background-color: darken($primary-color, 10%);
10 }
11
12 .icon {
13 margin-right: 0.5rem;
14 }
15}3. CSS-in-JS
Next.js prend également en charge les bibliothèques CSS-in-JS comme styled-components et emotion. Pour ces bibliothèques, une configuration supplémentaire est nécessaire pour fonctionner avec le SSR (Server-Side Rendering) :
1// components/StyledButton.tsx
2import styled from 'styled-components';
3
4const StyledButton = styled.button`
5 padding: 0.75rem 1.5rem;
6 background-color: #3a86ff;
7 color: white;
8 border: none;
9 border-radius: 0.25rem;
10
11 &:hover {
12 background-color: #2563eb;
13 }
14`;
15
16export default function Button({ children }) {
17 return <StyledButton>{children}</StyledButton>;
18}Pour que styled-components fonctionne avec le SSR, tu dois créer ton propre document dans Next.js :
1// app/registry.tsx
2'use client';
3
4import { useState } from 'react';
5import { useServerInsertedHTML } from 'next/navigation';
6import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
7
8export default function StyledComponentsRegistry({
9 children,
10}: {
11 children: React.ReactNode;
12}) {
13 const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
14
15 useServerInsertedHTML(() => {
16 const styles = styledComponentsStyleSheet.getStyleElement();
17 styledComponentsStyleSheet.instance.clearTag();
18 return <>{styles}</>;
19 });
20
21 if (typeof window !== 'undefined') return <>{children}</>;
22
23 return (
24 <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
25 {children}
26 </StyleSheetManager>
27 );
28}1// app/layout.tsx
2import StyledComponentsRegistry from './registry';
3import './globals.css';
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <html>
12 <body>
13 <StyledComponentsRegistry>{children}</StyledComponentsRegistry>
14 </body>
15 </html>
16 );
17}Exemples pratiques
Exemple 1 : créer un système de grille
1/* app/globals.css */
2.row {
3 display: flex;
4 flex-wrap: wrap;
5 margin: 0 -1rem;
6}
7
8.col {
9 padding: 0 1rem;
10}
11
12.col-1 { flex: 0 0 8.333%; max-width: 8.333%; }
13.col-2 { flex: 0 0 16.666%; max-width: 16.666%; }
14.col-3 { flex: 0 0 25%; max-width: 25%; }
15.col-4 { flex: 0 0 33.333%; max-width: 33.333%; }
16.col-5 { flex: 0 0 41.666%; max-width: 41.666%; }
17.col-6 { flex: 0 0 50%; max-width: 50%; }
18.col-7 { flex: 0 0 58.333%; max-width: 58.333%; }
19.col-8 { flex: 0 0 66.666%; max-width: 66.666%; }
20.col-9 { flex: 0 0 75%; max-width: 75%; }
21.col-10 { flex: 0 0 83.333%; max-width: 83.333%; }
22.col-11 { flex: 0 0 91.666%; max-width: 91.666%; }
23.col-12 { flex: 0 0 100%; max-width: 100%; }
24
25@media (max-width: 768px) {
26 .col-md-12 { flex: 0 0 100%; max-width: 100%; }
27 .col-md-6 { flex: 0 0 50%; max-width: 50%; }
28 .col-md-4 { flex: 0 0 33.333%; max-width: 33.333%; }
29}
30
31@media (max-width: 576px) {
32 .col-sm-12 { flex: 0 0 100%; max-width: 100%; }
33 .col-sm-6 { flex: 0 0 50%; max-width: 50%; }
34}Utilisation dans un composant :
1// app/page.tsx
2export default function Home() {
3 return (
4 <div className="container">
5 <div className="row">
6 <div className="col col-4 col-md-6 col-sm-12">
7 <div className="card">Kolumna 1</div>
8 </div>
9 <div className="col col-4 col-md-6 col-sm-12">
10 <div className="card">Kolumna 2</div>
11 </div>
12 <div className="col col-4 col-md-12 col-sm-12">
13 <div className="card">Kolumna 3</div>
14 </div>
15 </div>
16 </div>
17 );
18}Exemple 2 : styliser des formulaires
1/* Form.module.css */
2.form {
3 margin-bottom: 2rem;
4}
5
6.formGroup {
7 margin-bottom: 1rem;
8}
9
10.label {
11 display: block;
12 margin-bottom: 0.5rem;
13 font-weight: 500;
14}
15
16.input {
17 display: block;
18 width: 100%;
19 padding: 0.75rem;
20 font-size: 1rem;
21 border: 1px solid #ddd;
22 border-radius: var(--border-radius);
23 background-color: white;
24}
25
26.input:focus {
27 outline: none;
28 border-color: var(--primary-color);
29 box-shadow: 0 0 0 3px rgba(58, 134, 255, 0.2);
30}
31
32.error {
33 color: var(--accent-color);
34 font-size: 0.875rem;
35 margin-top: 0.25rem;
36}
37
38.submitButton {
39 composes: button from './Button.module.css';
40 composes: primary from './Button.module.css';
41}Bonnes pratiques
Maintiens une structure cohérente
- Les styles globaux dans
app/globals.css - Les modules CSS à côté des composants
- Un nommage de fichier cohérent (par ex.
ComponentName.module.css)
- Les styles globaux dans
Utilise des variables CSS pour les valeurs récurrentes
- Les couleurs
- Les espacements
- Les tailles de police
- Les rayons de bordure
- Les ombres
Crée des classes utilitaires pour les styles fréquemment utilisés
.text-center,.mb-2, etc.
Utilise des commentaires pour une meilleure organisation
1/* 2 * TYPOGRAPHY 3 * ------------- 4 */ 5 6/* 7 * LAYOUT 8 * ------------- 9 */Applique des méthodologies CSS (si nécessaire)
- BEM (Block Element Modifier)
- SMACSS (Scalable and Modular Architecture for CSS)
- OOCSS (Object-Oriented CSS)
Préfère la composition à l'héritage
- Combine de petites classes à usage unique plutôt que de créer de grands sélecteurs complexes
Performance et style
Next.js 16 optimise automatiquement le CSS :
- Lors du build de production, le CSS est minifié
- Les CSS Modules sont traités et des noms de classe uniques sont générés
- Les styles critiques sont automatiquement injectés dans la balise
<head>
Pour les applications plus grandes, il vaut la peine d'envisager :
Le code splitting du CSS
- Le CSS est divisé en fichiers plus petits et chargé uniquement quand c'est nécessaire
- Dans Next.js, cela se fait automatiquement pour les CSS Modules
L'utilisation d'outils pour éliminer le CSS inutilisé
- PurgeCSS
- Unused CSS (ucss)
Exemples étendus et applications
Système de composants utilisant les CSS Modules
Voici un exemple de système de composants étendu utilisant les CSS Modules dans une application Next.js 16 :
- Structure des répertoires :
1components/
2├── ui/
3│ ├── Button/
4│ │ ├── Button.tsx
5│ │ └── Button.module.css
6│ ├── Card/
7│ │ ├── Card.tsx
8│ │ └── Card.module.css
9│ ├── Input/
10│ │ ├── Input.tsx
11│ │ └── Input.module.css
12│ └──
13├── layout/
14│ ├── Header/
15│ │ ├── Header.tsx
16│ │ └── Header.module.css
17│ ├── Footer/
18│ │ ├── Footer.tsx
19│ │ └── Footer.module.css
20│ └──
21└──- Le composant Button avec différentes variantes :
1// components/ui/Button/Button.tsx
2import styles from './Button.module.css';
3import { ReactNode } from 'react';
4
5type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'outline' | 'text';
6type ButtonSize = 'sm' | 'md' | 'lg';
7
8interface ButtonProps {
9 variant?: ButtonVariant;
10 size?: ButtonSize;
11 children: ReactNode;
12 onClick?: () => void;
13 disabled?: boolean;
14 fullWidth?: boolean;
15 icon?: ReactNode;
16 iconPosition?: 'left' | 'right';
17 className?: string;
18}
19
20export function Button({
21 variant = 'primary',
22 size = 'md',
23 children,
24 onClick,
25 disabled = false,
26 fullWidth = false,
27 icon,
28 iconPosition = 'left',
29 className = '',
30}: ButtonProps) {
31 const buttonClasses = [
32 styles.button,
33 styles[variant],
34 styles[size],
35 fullWidth ? styles.fullWidth : '',
36 icon ? styles.hasIcon : '',
37 icon && iconPosition === 'right' ? styles.iconRight : '',
38 disabled ? styles.disabled : '',
39 className
40 ].filter(Boolean).join(' ');
41
42 return (
43 <button
44 className={buttonClasses}
45 onClick={onClick}
46 disabled={disabled}
47 >
48 {icon && iconPosition === 'left' && (
49 <span className={styles.icon}>{icon}</span>
50 )}
51 <span className={styles.text}>{children}</span>
52 {icon && iconPosition === 'right' && (
53 <span className={styles.icon}>{icon}</span>
54 )}
55 </button>
56 );
57}1/* components/ui/Button/Button.module.css */
2.button {
3 display: inline-flex;
4 align-items: center;
5 justify-content: center;
6 font-weight: 500;
7 border: none;
8 border-radius: var(--border-radius);
9 cursor: pointer;
10 transition: all 0.2s ease;
11 font-family: inherit;
12}
13
14/* Variants */
15.primary {
16 background-color: var(--primary-color);
17 color: white;
18}
19
20.primary:hover {
21 background-color: var(--primary-dark);
22}
23
24.secondary {
25 background-color: var(--secondary-color);
26 color: white;
27}
28
29.secondary:hover {
30 background-color: var(--secondary-dark);
31}
32
33.tertiary {
34 background-color: var(--tertiary-color);
35 color: white;
36}
37
38.tertiary:hover {
39 background-color: var(--tertiary-dark);
40}
41
42.outline {
43 background-color: transparent;
44 border: 1px solid var(--primary-color);
45 color: var(--primary-color);
46}
47
48.outline:hover {
49 background-color: rgba(58, 134, 255, 0.1);
50}
51
52.text {
53 background-color: transparent;
54 color: var(--primary-color);
55 padding-left: 0;
56 padding-right: 0;
57}
58
59.text:hover {
60 background-color: transparent;
61 color: var(--primary-dark);
62 text-decoration: underline;
63}
64
65/* Sizes */
66.sm {
67 font-size: 0.875rem;
68 padding: 0.5rem 1rem;
69}
70
71.md {
72 font-size: 1rem;
73 padding: 0.75rem 1.5rem;
74}
75
76.lg {
77 font-size: 1.125rem;
78 padding: 1rem 2rem;
79}
80
81/* Modifiers */
82.fullWidth {
83 width: 100%;
84}
85
86.hasIcon {
87 gap: 0.5rem;
88}
89
90.iconRight {
91 flex-direction: row-reverse;
92}
93
94.disabled {
95 opacity: 0.6;
96 cursor: not-allowed;
97}
98
99.disabled:hover {
100 background-color: var(--primary-color);
101}
102
103.outline.disabled:hover {
104 background-color: transparent;
105}
106
107.text.disabled:hover {
108 background-color: transparent;
109 text-decoration: none;
110}
111
112.icon {
113 display: flex;
114 align-items: center;
115 justify-content: center;
116}
117
118.button .text {
119 display: inline-block;
120}- Utilisation du composant Button :
1// app/examples/page.tsx
2import { Button } from '@/components/ui/Button/Button';
3import { FiDownload, FiHeart, FiArrowRight } from 'react-icons/fi';
4
5export default function ButtonExamplesPage() {
6 return (
7 <div className="container">
8 <h1>Button Examples</h1>
9
10 <h2>Warianty</h2>
11 <div className="button-group">
12 <Button variant="primary">Primary</Button>
13 <Button variant="secondary">Secondary</Button>
14 <Button variant="tertiary">Tertiary</Button>
15 <Button variant="outline">Outline</Button>
16 <Button variant="text">Text</Button>
17 </div>
18
19 <h2>Tailles</h2>
20 <div className="button-group">
21 <Button size="sm">Small</Button>
22 <Button size="md">Medium</Button>
23 <Button size="lg">Large</Button>
24 </div>
25
26 <h2>Z ikonami</h2>
27 <div className="button-group">
28 <Button icon={<FiDownload />}>Télécharger</Button>
29 <Button icon={<FiHeart />} variant="outline">Polub</Button>
30 <Button icon={<FiArrowRight />} iconPosition="right">
31 Continue
32 </Button>
33 </div>
34
35 <h2>Full Width</h2>
36 <Button fullWidth>Full Width Button</Button>
37
38 <h2>Disabled</h2>
39 <div className="button-group">
40 <Button disabled>Disabled Button</Button>
41 <Button variant="outline" disabled>Disabled Outline</Button>
42 </div>
43 </div>
44 );
45}Résumé
Le style dans Next.js 16 est flexible et autorise différentes approches, des styles globaux aux CSS Modules encapsulés. Comme à Quantum Metropolis, où l'esthétique de la ville entière est cohérente mais où chaque quartier conserve son caractère unique, dans les applications Next.js nous pouvons combiner des règles globales avec des styles de composant locaux.
Points clés à retenir :
- Les styles globaux sont idéaux pour définir des règles générales, des variables et des classes utilitaires
- Les CSS Modules offrent un style local sans conflit, idéal pour les composants
- Next.js 16 prend aussi en charge Sass, Styled JSX et les bibliothèques CSS-in-JS
- De bonnes pratiques d'organisation des styles améliorent la lisibilité et facilitent la maintenance du code
Dans le prochain chapitre, nous étudierons l'intégration de Tailwind CSS, un framework CSS utility-first populaire qui peut considérablement accélérer le processus de style dans Next.js 16.
Code de cette leçon : app/layout.tsx
1// Root Layout with Global Styles
2import { ReactNode } from 'react';
3import './globals.css';
4
5interface RootLayoutProps {
6 children: ReactNode;
7}
8
9export const metadata = {
10 title: 'Metropolis Quantum - Styling System',
11 description: 'CSS Modules and Global Styles in Next.js 16',
12};
13
14export default function RootLayout({ children }: RootLayoutProps) {
15 console.log("Styling system initialized");
16
17 return (
18 <html lang="en" className="theme-system">
19 <body>
20 <div className="metropolis-app">
21 <header className="global-header">
22 <div className="header-container">
23 <h1 className="logo">Metropolis Quantum</h1>
24 <nav className="main-nav">
25 <a href="/" className="nav-link">Home</a>
26 <a href="/themes" className="nav-link">Themes</a>
27 <a href="/components" className="nav-link">Components</a>
28 <a href="/animations" className="nav-link">Animations</a>
29 </nav>
30 <button className="theme-toggle" onclick="toggleTheme()">
31 Dark Mode
32 </button>
33 </div>
34 </header>
35
36 <main className="main-content">
37 {children}
38 </main>
39
40 <footer className="global-footer">
41 <p>Styled with CSS Modules & Global CSS • Next.js 16</p>
42 </footer>
43 </div>
44 </body>
45 </html>
46 );
47}Tu as repéré une erreur dans cette leçon ?