Kurs JavaScript i React · Moduł 14: Zaawansowane stylowanie

CSS Modules - Izolowane Panele Sterowania

4 min czytania
W tej lekcji8

CSS Modules to jeden z najpopularniejszych sposobów stylowania w React. Działa jak system izolowanych paneli sterowania na statku kosmicznym -- każdy moduł ma swoje własne kontrolki, które nie kolidują z innymi.

Czym są CSS Modules?

CSS Modules to zwykłe pliki CSS z rozszerzeniem .module.css. Różnica polega na tym, że wszystkie nazwy klas są automatycznie unikalne -- React generuje unikalne identyfikatory, dzięki czemu style z jednego komponentu nigdy nie nadpiszą stylów innego.

1/* SpacePanel.module.css */
2.panel {
3  background: #0d1137;
4  border: 2px solid #3949ab;
5  border-radius: 12px;
6  padding: 20px;
7}
8
9.title {
10  color: #7c4dff;
11  font-size: 24px;
12  margin-bottom: 16px;
13}
14
15.statusActive {
16  color: #00e676;
17  font-weight: bold;
18}

Importowanie i używanie

Importujemy CSS Module jako obiekt i odwołujemy się do klas jak do właściwości obiektu:

1import styles from './SpacePanel.module.css';
2
3function SpacePanel({ title, status }) {
4  return (
5    <div className={styles.panel}>
6      <h2 className={styles.title}>{title}</h2>
7      <span className={styles.statusActive}>
8        Status: {status}
9      </span>
10    </div>
11  );
12}

W wygenerowanym HTML klasa panel stanie się czymś w stylu SpacePanel_panel_x7k2f -- całkowicie unikalna!

Łączenie klas

Często potrzebujemy łączyć kilka klas CSS. W CSS Modules możemy to robić na kilka sposobów:

1// Template literal
2<div className={`${styles.panel} ${styles.dark}`}>
3
4// Z warunkiem
5<div className={`${styles.panel} ${isActive ? styles.active : ''}`}>
6
7// Tablica z join
8<div className={[styles.panel, styles.dark].join(' ')}>

Compose -- dziedziczenie stylów

CSS Modules oferują specjalną dyrektywę composes, która pozwala dziedziczyć style z innych klas:

1/* base.module.css */
2.baseButton {
3  padding: 10px 20px;
4  border: none;
5  border-radius: 6px;
6  cursor: pointer;
7  font-size: 14px;
8  transition: all 0.3s ease;
9}
10
11/* SpaceButton.module.css */
12.primaryButton {
13  composes: baseButton from './base.module.css';
14  background: #7c4dff;
15  color: white;
16}
17
18.dangerButton {
19  composes: baseButton from './base.module.css';
20  background: #f44336;
21  color: white;
22}

Dzięki composes unikamy duplikowania stylów, zachowując jednocześnie izolację.

Globalne style w CSS Modules

Jeżeli potrzebujesz klasy globalnej (np. dla zewnętrznych bibliotek), użyj :global:

1/* Layout.module.css */
2:global(.container) {
3  max-width: 1200px;
4  margin: 0 auto;
5}
6
7.localClass {
8  /* To jest lokalne */
9  color: #64b5f6;
10}

Dynamiczne klasy z CSS Modules

Często potrzebujemy zmieniać style na podstawie propsów lub stanu. Oto kilka wzorców:

1import styles from './Alert.module.css';
2
3function Alert({ type = 'info', message }) {
4  // Dynamiczne wybieranie klasy na podstawie propsa
5  const alertClass = styles[type]; // styles.info, styles.warning, styles.error
6
7  return (
8    <div className={`${styles.alert} ${alertClass}`}>
9      <p className={styles.message}>{message}</p>
10    </div>
11  );
12}
1/* Alert.module.css */
2.alert {
3  padding: 16px;
4  border-radius: 8px;
5  border-left: 4px solid;
6}
7
8.info {
9  background: #1a237e;
10  border-color: #64b5f6;
11  color: #90caf9;
12}
13
14.warning {
15  background: #4a3800;
16  border-color: #ffa726;
17  color: #ffcc80;
18}
19
20.error {
21  background: #4a0000;
22  border-color: #f44336;
23  color: #ef9a9a;
24}

Zwróć uwagę, że styles[type] pozwala dynamicznie wybierać klasę na podstawie zmiennej -- to jak przełączanie trybów na panelu sterowania.

Biblioteka classnames / clsx

Do bardziej złożonych kombinacji klas warto używać biblioteki clsx lub classnames:

1import clsx from 'clsx';
2import styles from './Button.module.css';
3
4function SpaceButton({ variant, size, disabled }) {
5  return (
6    <button className={clsx(
7      styles.button,
8      styles[variant],     // styles.primary lub styles.secondary
9      styles[size],         // styles.small lub styles.large
10      { [styles.disabled]: disabled }  // warunkowo
11    )}>
12      Engage!
13    </button>
14  );
15}

Zalety CSS Modules

  • Izolacja stylów -- brak konfliktów nazw klas, każdy komponent ma swoją "kapsułę"
  • Zwykły CSS -- nie trzeba się uczyć nowej składni, używasz tego samego CSS co zawsze
  • Wsparcie natywne w Create React App i Next.js -- zero konfiguracji
  • Lekkość -- brak dodatkowych bibliotek w bundlu, zero runtime JS
  • Łatwa migracja z istniejącego CSS -- wystarczy zmienić rozszerzenie pliku i import
  • Typowanie -- można generować typy TypeScript dla klas CSS (np. przez typed-css-modules)

CSS Modules to solidny, sprawdzony wybór do stylowania komponentów React. Są jak niezawodne panele sterowania na statku -- proste, przewidywalne i bezkonfliktowe.

Kod do tej lekcji: App.jsx
1import React from 'react';
2import styles from './SpacePanel.module.css';
3
4function StatusIndicator({ label, status }) {
5  const statusClass = status === 'active'
6    ? styles.statusActive
7    : status === 'warning'
8    ? styles.statusWarning
9    : styles.statusCritical;
10
11  return (
12    <div className={styles.statusRow}>
13      <span className={styles.label}>{label}</span>
14      <span className={statusClass}>{status.toUpperCase()}</span>
15    </div>
16  );
17}
18
19function SpacePanel({ title, children }) {
20  return (
21    <div className={styles.panel}>
22      <h2 className={styles.title}>{title}</h2>
23      {children}
24    </div>
25  );
26}
27
28export default function App() {
29  return (
30    <div className={styles.app}>
31      <h1 className={styles.heading}>CSS Modules w React</h1>
32      <p className={styles.subtitle}>Izolowane style -- kazdy komponent ma swoje unikalne klasy</p>
33
34      <SpacePanel title="System nawigacyjny">
35        <StatusIndicator label="Silnik glowny" status="active" />
36        <StatusIndicator label="Oslona termiczna" status="warning" />
37        <StatusIndicator label="Paliwo zapasowe" status="critical" />
38      </SpacePanel>
39
40      <SpacePanel title="Komunikacja">
41        <StatusIndicator label="Lacze radiowe" status="active" />
42        <StatusIndicator label="Antena zapasowa" status="active" />
43        <StatusIndicator label="Sygnal SOS" status="active" />
44      </SpacePanel>
45    </div>
46  );
47}

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jaka jest prawidłowa składnia odwołania do CSS Variable w arkuszu stylów?

  2. 2. Co jest główną zaletą CSS Modules w porównaniu ze zwykłymi plikami CSS?

Zadania praktyczne w grze

  • Edytor kodu

    Zaimplementuj komponent AlertBox z CSS Modules

  • Klikanie w kolejności

    Ułóż składnię importu CSS Module w React:

  • Edytor kodu

    Zaimplementuj komponent zakładek z CSS Modules i useState

Przydatne artykuły