Menu

CSS w React: className, style inline, CSS Modules, Tailwind

Komponenty Reacta stylujesz przez className i zwykły CSS, przez prop style dla wartości wyliczanych w JavaScripcie, przez CSS Modules dla klas o ograniczonym zasięgu albo klasami narzędziowymi Tailwind. Poznaj każdy sposób, warunkowe klasy i to, kiedy czego używać.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Komponenty Reacta styluje się zwykłym CSS. Nadaj elementom klasę propsem className i zapisz reguły w arkuszu stylów, użyj propsa style dla wartości pochodzących z JavaScriptu, a po CSS Modules albo Tailwind sięgnij, gdy projekt urośnie. Przykład poniżej definiuje swój CSS w elemencie <style>, żeby mógł działać na tej stronie; w projekcie znajdowałby się w pliku .css.

Zmień #2563eb na #16a34a w regule .btn, a przycisk zrobi się zielony. Wszystko, co wiesz o CSS, nadal obowiązuje: selektory, media queries, stany hover, animacje.

className, a nie class

JSX kompiluje się do JavaScriptu, w którym class jest słowem zastrzeżonym, więc React używa className, czyli nazwy, której dla tej właściwości używa sam DOM (element.className). Przeglądarka wciąż dostaje zwykły atrybut class. Ta sama zmiana nazwy dotyczy htmlFor zamiast for na etykietach. React 19 akceptuje class z ostrzeżeniem w trybie deweloperskim, ale className to poprawna nazwa i ta, której używa każdy projekt.

className przyjmuje tekst, więc kilka klas oddziela się spacjami: className="btn btn-primary". Ponieważ wartość jest JavaScriptem, można ją wyliczyć.

Warunkowe klasy

Żeby dodać klasę tylko w niektórych przypadkach, zbuduj tekst operatorem warunkowym albo szablonem tekstowym. Klasycznym przykładem jest pasek kart, który wyróżnia wybraną kartę.

Kliknij Lessons, a podkreślenie się przesunie, bo teraz tylko tekst tego przycisku zawiera active. Reviews dostaje klasę disabled i atrybut disabled, więc jest szary i ignoruje kliknięcia. Szablon tekstowy zostawia dodatkowe spacje, gdy warunek jest fałszywy, co przeglądarki ignorują. Gdy komponent ma wiele warunkowych klas, tablica jest bardziej uporządkowana:

const classes = ['tab', isActive && 'active', isDisabled && 'disabled']
    .filter(Boolean)
    .join(' ');

Wiele projektów używa do tego samego malutkiego pakietu clsx: clsx('tab', { active: isActive, disabled: isDisabled }).

Prop style

Prop style przyjmuje obiekt JavaScript, a nie tekst. Dlatego ma podwójne nawiasy: zewnętrzna para otwiera wyrażenie JavaScript, wewnętrzna to literał obiektu. Nazwy właściwości są w camelCase (backgroundColor, fontSize, borderRadius), a wartości to teksty albo liczby. Liczba przy właściwości długości staje się pikselami, więc padding: 12 oznacza 12px.

Style inline sprawdzają się najlepiej, gdy wartość jest wyliczana podczas renderowania, na przykład szerokość paska postępu.

Klikaj Add 10%, aż pasek się wypełni i zrobi się zielony. Zwróć uwagę na width: percent + '%': sama liczba oznaczałaby piksele, więc jednostki inne niż px podaje się w tekście. Właściwości bez jednostki pozostają zwykłymi liczbami, jak opacity: 0.8, zIndex: 2, flexGrow: 1 i lineHeight: 1.5 (który jest mnożnikiem, a nie pikselami).

Style inline mają ograniczenia. Nie wyrażą :hover, :focus, media queries ani animacji keyframe, a każdy element nosi własną kopię reguł. Używaj ich do wartości dynamicznych, a resztę trzymaj w CSS.

Zmienne CSS z propsów

Dobrym kompromisem jest ustawienie własnej właściwości CSS w style i używanie jej w arkuszu stylów. Reguły zostają w CSS, łącznie ze stanami hover, a z JavaScriptu pochodzi tylko wartość.

Wybierz nowy kolor, a oba przyciski za nim pójdą, a wypełnienie przy hover nadal działa, bo to zwykły CSS. Nazwy własnych właściwości zachowują myślniki w obiekcie style, więc zapisuje się je w cudzysłowie: { '--accent': accent }.

Pliki CSS

W prawdziwym projekcie piszesz style w plikach .css i importujesz je z komponentu, który ich potrzebuje. Z Vite wystarczy sam import: narzędzie do budowania widzi import './Button.css', w trybie deweloperskim dodaje arkusz stylów do strony, a w wersji produkcyjnej pakuje go do pliku CSS. Nie ma tu eksportu do użycia; import istnieje tylko dla efektu ubocznego.

// Button.jsx
import './Button.css';

export default function Button({ children }) {
    return <button className="button">{children}</button>;
}
/* Button.css */
.button {
    background: #2563eb;
    color: white;
    border-radius: 6px;
}

Haczyk polega na tym, że każdy zaimportowany arkusz stylów jest globalny. Reguła .button w Button.css styluje każdy element z tą klasą, w dowolnym miejscu aplikacji, a dwa pliki, które definiują .title, nadpisują się nawzajem. Zespoły radzą sobie z tym konwencjami nazewnictwa, takimi jak BEM (.card__title), albo przez CSS Modules.

CSS Modules

Plik kończący się na .module.css to CSS Module. Jego import daje obiekt, który przypisuje każdej napisanej przez ciebie nazwie klasy unikalną wygenerowaną nazwę, więc klasa może działać tylko tam, gdzie jej używasz. Vite i Next.js obsługują to bez konfiguracji.

// Card.jsx
import styles from './Card.module.css';

export default function Card({ title, children, featured }) {
    return (
        <section className={featured ? `${styles.card} ${styles.featured}` : styles.card}>
            <h3 className={styles.title}>{title}</h3>
            {children}
        </section>
    );
}
/* Card.module.css */
.card { border: 1px solid #ddd; border-radius: 10px; padding: 16px; }
.featured { border-color: #2563eb; }
.title { margin: 0; }

W przeglądarce klasa wychodzi jako coś w stylu _card_1x2ab_1. Inny komponent może zdefiniować własne .title i te dwie nigdy nie kolidują. Piszesz normalny CSS, z regułami hover i media queries włącznie, dlatego CSS Modules są częstym domyślnym wyborem dla stylów komponentów.

Tailwind CSS z React

Tailwind działa inaczej: zamiast pisać reguły, składasz małe klasy narzędziowe bezpośrednio w className. px-4 ustawia padding poziomy, rounded-lg zaokrągla rogi, hover:bg-blue-700 zmienia tło przy hover. Tailwind skanuje twoje pliki i generuje CSS tylko dla klas, których używasz.

Konfiguracja w aplikacji React z Vite (Tailwind v4) to trzy kroki:

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
    plugins: [react(), tailwindcss()],
});
/* src/index.css, imported from main.jsx */
@import "tailwindcss";

Potem styluj komponenty klasami:

function UpgradeCard({ active }) {
    return (
        <div className="max-w-xs rounded-xl border border-gray-200 p-4">
            <h3 className="mb-2 text-lg font-semibold">Pro plan</h3>
            <button
                className={`rounded-md px-4 py-2 text-white ${active ? 'bg-green-600' : 'bg-blue-600 hover:bg-blue-700'}`}
            >
                {active ? 'Active' : 'Upgrade'}
            </button>
        </div>
    );
}

Tailwind nie jest dostępny w edytorach na tej stronie, więc pokazujemy go jako statyczny kod. Warunkowe klasy działają dokładnie tak jak w przykładzie z kartami powyżej, ale każdą nazwę klasy pisz w całości: Tailwind znajduje klasy, skanując tekst źródłowy, więc nazwa składana w czasie działania, taka jak `bg-${color}-600`, nigdy nie zostanie wygenerowana.

Kiedy czego używać

  • Zwykłe pliki CSS pasują do małych aplikacji i stylów globalnych (resety, czcionki, układ strony). Uważaj na kolizje nazw klas, gdy aplikacja rośnie.
  • CSS Modules pasują do większości stylów komponentów: normalny CSS, automatycznie ograniczony zasięg, żadnej dodatkowej biblioteki.
  • Tailwind pasuje do zespołów, które wolą stylować w znacznikach i chcą wspólnej skali projektowej dla odstępów i kolorów.
  • Prop style służy do wartości wyliczanych podczas renderowania: szerokości, pozycji, koloru wybranego przez użytkownika. Łącz go ze zmiennymi CSS, żeby reguły hover i media zostały w CSS.

Możesz je mieszać. Typowa aplikacja ma jeden globalny arkusz stylów, CSS Modules albo Tailwind dla komponentów i kilka stylów inline dla wartości dynamicznych. Biblioteki CSS-in-JS, takie jak styled-components i Emotion, to kolejna opcja, którą spotkasz w starszych projektach. Strona o instalacji Reacta pokazuje, jak założyć projekt Vite, w którym wszystko to działa.

Najczęściej zadawane pytania

Dlaczego React używa className zamiast class?

JSX kompiluje się do JavaScriptu, a class jest tam słowem zastrzeżonym. React używa nazwy właściwości DOM, className, i tak samo nazywa się element.className w zwykłym JavaScripcie. W HTML wciąż staje się zwykłym atrybutem class.

Jak pisać style inline w React?

Przekaż obiekt do propsa style, z nazwami właściwości w camelCase: style={{ backgroundColor: 'teal', fontSize: 18 }}. Zewnętrzne nawiasy otwierają wyrażenie JavaScript, a wewnętrzne to obiekt. Liczby stają się pikselami dla właściwości, które przyjmują długość.

Jak w React dodać klasę warunkowo?

Zbuduj tekst w JavaScripcie: className={isActive ? 'tab active' : 'tab'} albo szablonem tekstowym, na przykład className={`tab ${isActive ? 'active' : ''}`}. Przy wielu warunkach mały pomocnik, taki jak pakiet clsx, utrzymuje czytelność.

Czy pliki CSS w React są globalne?

Tak. import './App.css' dodaje arkusz stylów do całej strony, więc jego nazwy klas mogą kolidować z innymi plikami. CSS Modules (App.module.css) zmieniają nazwę każdej klasy na unikalną, więc działa ona tylko tam, gdzie ją importujesz.

Jak używać Tailwind z React?

W projekcie Vite zainstaluj tailwindcss i @tailwindcss/vite, dodaj wtyczkę do vite.config.js i umieść @import "tailwindcss"; na początku głównego pliku CSS. Potem pisz klasy narzędziowe w className, na przykład className="px-4 py-2 rounded bg-blue-600 text-white".

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ