Lekcja 28

Nazewnictwo klas i BEM-like naming

W małym pliku CSS przypadkowe nazwy klas wydają się niewinne. W większym projekcie szybko prowadzą do kolizji, nadpisywania stylów i kodu, którego nikt nie chce ruszać. W tej lekcji nauczysz się nadawać klasom nazwy, które opisują komponent, jego części i warianty.

Cele lekcji

Po ukończeniu tej lekcji będziesz umieć:

  • rozpoznać nazwy klas, które będą trudne w utrzymaniu,
  • wyjaśnić różnicę między blokiem, elementem i modyfikatorem,
  • pisać klasy w stylu block__element--modifier,
  • odróżniać klasę komponentu od klasy stanu i utility,
  • unikać zbyt głębokiego zagnieżdżania selektorów,
  • projektować nazwy klas tak, aby były odporne na rozbudowę komponentu.

Kontekst praktyczny

Nazewnictwo klas jest podstawą pracy zespołowej. Gdy komponent ma jasne klasy, łatwiej go znaleźć, rozszerzyć i naprawić. Dobre nazwy zmniejszają zależność od struktury HTML i ograniczają ryzyko, że zmiana w jednej sekcji przypadkowo popsuje inną.

W praktyce: BEM-like naming nie jest religią składni. To prosty kontrakt: klasa mówi, do jakiego komponentu należy, jaką część opisuje i czy jest wariantem.

Problem nazw ogólnych

Nazwy typu .box, .title, .green albo .left nie mówią, do czego należą. Im większy projekt, tym większa szansa, że taka klasa zostanie użyta w kilku miejscach i zacznie wymuszać nadpisywanie stylów.

.box {
  padding: 1rem;
}

.title {
  font-size: 1.25rem;
}

.green {
  background: #dcfce7;
}

Te nazwy opisują wygląd albo położenie, ale nie opisują roli komponentu. Po kilku tygodniach nie wiadomo, czy .box jest kartą lekcji, panelem formularza czy kontenerem promocji.

Model BEM-like

BEM dzieli nazwę klasy na trzy pojęcia: blok, element i modyfikator. W praktyce frontendowej często używa się wersji BEM-like, czyli tej samej logiki bez nadmiernego formalizmu.

.course-card {}
.course-card__title {}
.course-card__meta {}
.course-card--featured {}

.course-card jest samodzielnym komponentem. __title i __meta są częściami tego komponentu. --featured jest wariantem całego komponentu.

Blok

Blok to samodzielny komponent, który można przenieść w inne miejsce strony bez zmiany jego sensu. Dobry blok ma nazwę rzeczownika albo krótkiego wyrażenia opisującego rolę.

.pricing-card {
  display: grid;
  gap: .75rem;
  padding: 1rem;
  border: 1px solid var(--color-border);
}

Nazwa .pricing-card mówi więcej niż .card, jeśli w projekcie istnieją też karty lekcji, karty produktu i karty profilu.

Element

Element to część bloku, która nie ma sensu jako samodzielny komponent. Zapisujemy go po podwójnym podkreśleniu: block__element.

.pricing-card__title {
  margin: 0;
  font-size: 1.25rem;
}

.pricing-card__price {
  font-size: 2rem;
  font-weight: 800;
}

Nie twórz łańcuchów typu .pricing-card__header__title. Jeśli element zaczyna mieć własne podczęści, rozważ nowy blok albo prostszą strukturę.

Modyfikator

Modyfikator opisuje wariant bloku albo elementu. Zapisujemy go po podwójnym myślniku: block--modifier albo block__element--modifier.

.pricing-card--featured {
  border-color: #60a5fa;
  background: #eff6ff;
}

.pricing-card__badge--success {
  background: #dcfce7;
  color: #166534;
}

Modyfikator nie powinien istnieć bez klasy bazowej. Element powinien mieć najpierw .pricing-card, a dopiero potem .pricing-card--featured.

Stan i utility

Stan opisuje aktualną sytuację komponentu, na przykład aktywny, otwarty albo ładowany. Utility to mała klasa pomocnicza, która robi jedną rzecz. Nie mieszaj ich z nazwami komponentów bez potrzeby.

.accordion {
  border: 1px solid var(--color-border);
}

.accordion.is-open {
  border-color: #60a5fa;
}

.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

W tym projekcie możesz spotkać klasy stanu typu .is-open. Są czytelne, gdy opisują stan komponentu, ale nie powinny zastępować nazw jego części.

Demo nazewnictwa

Demo porównuje ten sam komponent opisany nazwami ogólnymi i nazwami BEM-like. Różnica nie polega na wyglądzie, tylko na tym, jak łatwo będzie utrzymać kod po rozbudowie.

Nieczytelnie

Nazwy ogólne

box title green Karta kursu

Wygląda poprawnie, ale klasy nie mówią, gdzie komponent żyje i co można bezpiecznie zmienić.

  • .boxzbyt ogólna
  • .titlekolizje
  • .greenopis wyglądu
BEM-like

Nazwy komponentu

course-card--featured Karta kursu

Klasy opisują blok, elementy i wariant, więc komponent można rozszerzać bez zgadywania.

  • .course-cardblok
  • .course-card__titleelement
  • .course-card--featuredwariant

Najczęstsze błędy początkujących

  • Nazywanie klas po kolorze, wielkości albo położeniu zamiast po roli komponentu.
  • Tworzenie zbyt ogólnych klas typu .card, .item, .content w dużym projekcie.
  • Zagnieżdżanie selektorów tak głęboko, że HTML staje się częścią kontraktu CSS.
  • Używanie modyfikatora bez klasy bazowej komponentu.
  • Mieszanie klas komponentu, stanu i utility bez jasnej zasady.
  • Zmiana nazwy klasy bez sprawdzenia, gdzie jest używana w HTML i JavaScript.

Mini zadanie

Przepisz prostą kartę profilu na nazwy BEM-like.

  • Wybierz blok, na przykład .profile-card.
  • Dodaj elementy: __avatar, __name, __role i __actions.
  • Dodaj modyfikator --compact albo --featured.
  • Dodaj stan .is-loading, jeśli karta ma wariant ładowania.
  • Sprawdź, czy żadna klasa nie opisuje wyłącznie koloru albo położenia.

Checklista

  • Potrafię wskazać blok, element i modyfikator w komponencie.
  • Wiem, kiedy nazwa klasy jest zbyt ogólna.
  • Nie tworzę klas zależnych od konkretnego miejsca w HTML.
  • Używam modyfikatorów do wariantów, a nie do zastępowania klasy bazowej.
  • Rozdzielam klasy komponentu, stanu i utility.
  • Projektuję nazwy tak, aby inna osoba mogła bezpiecznie rozbudować komponent.

Podsumowanie lekcji

Dobre nazwy klas są częścią architektury CSS. BEM-like naming pomaga utrzymać komponenty, bo jasno oddziela blok, jego elementy i warianty. Nie chodzi o długie nazwy dla samych nazw, tylko o przewidywalność i mniejsze ryzyko przypadkowych kolizji.

Kolejny krok roadmapy to zmienne CSS i design tokens.

Przejdź do Lekcji 29