Jak korzystać z modułów CSS z Create-React-App
"Jak zorganizowałbyś CSS w dużym projekcie?" - to pytanie, które zawsze zadaję, kiedy przeprowadzam rozmowy o pracę z młodszymi programistami. Zdziwiłbyś się, jak wielu developerów nie ma na nie odpowiedzi.
Wraz z rozwojem naszych aplikacji wzrasta również ryzyko kolizji nazw klas.
Spójrzmy na konkretny przykład:
.container {
width: 50%;
display: flex;
border: 1px solid black;
}
.container {
width: 100%;
height: 200px;
}
Tutaj użyliśmy nazwy klasy container
w dwóch różnych plikach CSS. Teraz elementy, którym nadajemy nazwę klasy container
będą miały wymieszane style, czego przecież nie chcemy.
W tym akurat przykładzie wygląda to całkiem trywialnie i łatwo takiej sytuacji uniknąć. Ale nie jest to już takie łatwe do uniknięcia, gdy pracujesz z wieloma osobami nad dużym projektem.
Jak zorganizować CSS w dużym projekcie?
W przeszłości programiści radzili sobie z globalnym charakterem CSS, opierając się na konwencjach nazewnictwa. Najpopularniejszym rozwiązaniem był BEM (Block Element Modifier). Wszystkie te rozwiązania miały jednak to samo ograniczenie: opierają się na staranności programistów, aby uniknąć kolizji nazw.
Co by było, gdybyśmy zamiast polegać na developerach używających unikalnych nazw klas, moglibyśmy polegać na narzędziu, które generuje dla nas nazwy klas podczas tworzenia? Na szczęście dla nas, to narzędzie już istnieje i nazywa się CSS Modules.
CSS Modules jest plikiem CSS, w którym wszystkie nazwy klas i nazwy animacji domyślnie mają zasięg lokalny.
Korzystanie z modułów CSS z Create-react-app
Na szczęście dla nas, moduły CSS są obsługiwane przez Create-react-app
domyślnie. Jedyne, co mamy do zrobienia, to nadanie odpowiedniej nazwy naszym plikom CSS. Jeśli zaimportujemy plik z rozszerzeniem .module.css
, to createe-react-app
automatycznie potraktuje go jako moduł CSS.
npx create-react-app css-modules-app
Otwórz projekt w swoim ulubionym edytorze. Zmień nazwę pliku App.css
na App.module.css
. Następnie zmień nazwę importu z import './App.css'
na import styles from './App.modules.css
. Wreszcie, gdziekolwiek używasz className, upewnij się, że używasz obiektu styles
zamiast bezpośredniego wstawiania nazwy klasy.
Więc zamiast pisać className="App"
napisałbyś className={styles['App']}
.
import React from "react";
import logo from "./logo.svg";
import styles from "./App.module.css";
function App() {
return (
<div className={styles["App"]}>
<header className={styles["App-header"]}>
<img src={logo} className={styles["App-logo"]} alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className={styles["App-link"]}
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Następnie uruchom aplikację i sprawdź, co otrzymasz. Zauważysz, że moduły CSS wygenerowały dla nas nazwy klas.
Nazwa klasy App-header
to teraz App_App-header__xLkWl
. Prefiks jest nazwą pliku App.module.css
. Następnie dodano podkreślenie i naszą oryginalną nazwę klasy: App-header
. Na koniec dodano wygenerowany hash xLkWl
. Pomaga to zapewnić, że nasza nazwa klasy pozostanie unikalna.
Pisanie stylów globalnych
Czasami trzeba pisać globalne style. Jest to szczególnie ważne, gdy trzeba zastąpić style z zewnętrznych komponentów. Robienie tego za pomocą modułów CSS jest bardzo proste. Wystarczy użyć selektora :Global
, aby przełączyć się z zasięgu lokalnego na globalny.
.container {
height: 200px;
width: 100%;
}
:global .React_Select {
border-color: green;
}
Komponowanie stylów warunkowych
Moduły CSS świetnie sprawdzają się w stylach warunkowych. Często musimy tworzyć komponenty, które mają różne oblicza w oparciu o ich propsy. Weźmy na przykład prosty komponent TextInput
.
Aby ułatwić sobie życie, zainstaluj zależność w postaci classnames
.
yarn add classnames
Następnie tworzymy dwa nowe pliki text-input.js
i text-input-module.css
.
Kod jest poniżej:
import React from "react";
import classNames from "classnames";
import styles from "./text-input.module.css";
const TextInput = props => {
return (
<input
className={classNames({
[styles["text-input"]]: true,
[styles["warning"]]: props.hasWarning,
[styles["error"]]: props.hasError,
})}
type="text"
/>
);
};
export default TextInput;
.text-input {
height: 32px;
width: 100%;
border: 1px solid black;
}
.warning {
border-color: orange;
}
.error {
border-color: red;
}
Gdy do TextInput
są przekazywane właściwości hasWarning
lub hasError
, zostaną dodane odpowiednie nazwy klasy.
Podsumowując
Korzystanie z modułów CSS pozwala nam na pisanie stylów o zasięgu lokalnym. Pomaga nam to uniknąć kolizji nazw pomiędzy naszymi nazwami klas. Zważając że wsparcie dla modułów CSS jest wbudowane w create-react-app
, nie musimy nawet wykonać komendy eject
, aby wykorzystać moduły CSS.
Oryginał tekstu w języku angielskim przeczytasz tutaj.