Nazewnictwo klas w SCSS robi największą różnicę wtedy, gdy komponenty są przewidywalne, łatwe do odczytania i nie wymagają zgadywania, co z czym jest powiązane. BEM porządkuje tę warstwę, a SCSS daje wygodny zapis bez rezygnowania z czytelności. Poniżej pokazuję, jak sensownie budować nazwy bloków, elementów i modyfikatorów, kiedy korzystać z zagnieżdżania oraz gdzie kończy się praktyka, a zaczyna chaos.
Najkrótsza droga do spójnych klas w SCSS
- Blok opisuje samodzielny komponent, a elementy i modyfikatory są od niego zależne.
- W SCSS najlepiej sprawdza się płytkie zagnieżdżanie z użyciem
&, bez rozbudowanych łańcuchów selektorów. - Selektory klasowe są w praktyce stabilniejsze niż tagi, identyfikatory i selektory potomków.
- Najlepsze efekty daje jedna, prosta konwencja używana konsekwentnie w całym projekcie.
- Dobrze nazwany komponent jest łatwiejszy do ponownego użycia, testowania i debugowania.
Dlaczego BEM dobrze współpracuje z SCSS
BEM i SCSS rozwiązują dwa różne problemy, ale razem tworzą bardzo sensowny duet. BEM porządkuje nazwy klas, a SCSS pomaga zapisać je wygodnie i powtarzalnie. W praktyce to ważne, bo samo zagnieżdżenie w SCSS nie naprawia złej architektury, tak samo jak sama konwencja nazw nie uchroni przed bałaganem, jeśli każdy pisze selektory po swojemu.
W dokumentacji Sass wprost pojawia się ostrzeżenie przed zbyt głębokim nestingiem. I dobrze, bo im bardziej rozbudowany staje się selektor, tym trudniej od razu zobaczyć, co właściwie zostanie wygenerowane. BEM daje prostą zasadę: komponent ma jeden blok, jego części są elementami, a warianty lub stany są modyfikatorami. Dzięki temu nie budujesz zależności na podstawie miejsca w DOM, tylko na podstawie roli komponentu.
| Obszar | Rola | Efekt w projekcie |
|---|---|---|
| BEM | Porządkuje nazwy klas | Łatwiej zrozumieć strukturę komponentu |
| SCSS | Ułatwia zapis i organizację reguł | Kod jest krótszy, ale nadal czytelny |
| Połączenie obu | Utrzymuje spójność przy rozwoju UI | Mniej konfliktów i mniej przypadkowej specyficzności |
To właśnie dlatego w większych projektach tak dobrze działa zasada: nazwa ma opisywać funkcję, a SCSS ma jedynie pomóc tę funkcję zapisać. Następny krok to konkretne reguły nazewnictwa, bo bez nich nawet dobry system szybko się rozmywa.
Jak zapisywać bloki, elementy i modyfikatory
Najprościej myśleć o tym tak: blok to samodzielny komponent, element to jego część, a modyfikator to wariant, stan albo wersja tego samego komponentu. W praktyce nazwa powinna być krótka, konkretna i oparta na znaczeniu, a nie na wyglądzie. Lepiej napisać product-card niż blue-box, bo kolor może się zmienić, a rola komponentu zostaje ta sama.
| Rodzaj klasy | Wzór | Przykład | Jak o tym myśleć |
|---|---|---|---|
| Blok | .block |
.product-card |
Samodzielny komponent, który może istnieć samodzielnie |
| Element | .block__elem |
.product-card__title |
Część bloku bez sensu poza nim |
| Modyfikator | .block--mod |
.product-card--featured |
Wariant, stan albo wersja komponentu |
Warto też pilnować jednego prostego założenia: blok powinien być rzeczownikiem, a nie opisem koloru, rozmiaru czy układu. Wtedy nazwa nie starzeje się po pierwszym rebrandingu albo po zmianie projektu graficznego. Dobrze działa też zasada, że modyfikator nie zastępuje klasy bazowej, tylko ją uzupełnia.
Słuchawki bezprzewodowe
249 zł
Ten zapis jest czytelny od razu: wiadomo, co jest bazą, co jest częścią komponentu, a co wariantem. I właśnie dlatego BEM tak dobrze scala się z SCSS, bo kolejne reguły można dopisać bez rozjeżdżania całej struktury.
Gdzie kończy się wygodne zagnieżdżanie SCSS
SCSS zachęca do zagnieżdżania, ale nie każdy nesting jest dobry. Ja zwykle trzymam się zasady, że zagnieżdżenie ma pomagać w odczytaniu komponentu, a nie budować ukrytego labiryntu selektorów. W przypadku BEM najczęściej wystarczy jedna warstwa, na przykład dla elementów i modyfikatorów zapisanych przez &.
.product-card {
padding: 1rem;
border: 1px solid var(--border-color);
&__title {
font-size: 1rem;
font-weight: 600;
}
&__price {
color: var(--accent-color);
font-weight: 700;
}
&--featured {
border-color: #d4a017;
}
&:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
}To jest wygodny poziom zagnieżdżenia, bo od razu widać, że wszystkie reguły dotyczą jednego komponentu. Zupełnie inna sytuacja zaczyna się wtedy, gdy ktoś pisze selektory w stylu .page .sidebar .product-card .title albo buduje kilka poziomów potomków tylko po to, by „ładnie” wyglądało w pliku SCSS. W CSS wynikowym zwykle kończy się to nadmierną specyficznością, trudnym nadpisywaniem i problemami z wyszukiwaniem klas w kodzie.
Warto też odróżnić selector nesting od pseudo-klas i stanów. &:hover, &::before czy nawet &.is-active mają sens, bo opisują bezpośrednio ten sam komponent. Problem zaczyna się dopiero wtedy, gdy nesting próbuje zastąpić architekturę klas. Natywne zagnieżdżanie CSS nie zmienia tu zasad gry: technika jest nowsza, ale logika czytelnego komponentu pozostaje ta sama.
Jeżeli po kompilacji musisz mentalnie odtwarzać, jak wygląda selektor wynikowy, to zwykle znak, że zaszło się za daleko. Następna sekcja pokazuje, jak wygląda poprawny zapis w praktyce, bez teoretyzowania.
Jak wygląda poprawny komponent w praktyce
Najlepiej widać to na prostym komponencie e-commerce, takim jak karta produktu. To dobry przykład, bo ma część wspólną, kilka elementów i ewentualny wariant promocyjny. W takim układzie łatwo też pokazać, dlaczego nie każdy fragment musi być „dzieckiem” jednego bloku.
Przeczytaj również: Margin w CSS i dokumentach - Jak używać, by nie psuć layoutu?
Słuchawki bezprzewodowe
249 zł
.product-card {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--border-color);
border-radius: 1rem;
background: #fff;
&__media {
aspect-ratio: 1 / 1;
overflow: hidden;
border-radius: 0.75rem;
}
&__image {
width: 100%;
height: 100%;
object-fit: cover;
}
&__title {
margin: 0;
font-size: 1rem;
line-height: 1.3;
}
&__price {
margin: 0;
font-size: 1.125rem;
font-weight: 700;
}
&__cta {
justify-self: start;
}
&--featured {
border-color: #d4a017;
box-shadow: 0 12px 28px rgba(212, 160, 23, 0.18);
}
}Najważniejszy szczegół w tym przykładzie to przycisk. Ja nie traktowałbym go jako elementu wyłącznie jednej karty, jeśli ma pojawiać się również w innych miejscach serwisu. Lepiej wtedy nadać mu własny blok button i ewentualnie dodać klasę pomocniczą w obrębie karty. Dzięki temu komponent pozostaje współdzielony, a karta produktu nie przejmuje cudzej odpowiedzialności.
Taki zapis dobrze skaluje się w sklepach internetowych, katalogach ofert i landing page’ach, gdzie podobne moduły wracają bardzo często. Gdy masz już ten wzorzec, trzeba jeszcze wiedzieć, jakich błędów nie popełniać, bo one najczęściej psują nawet dobrze rozpoczęty system.
Najczęstsze błędy i kiedy konwencja zaczyna przeszkadzać
Najczęściej widzę pięć błędów, które szybko rozwalają spójność klas. Nie są spektakularne, ale właśnie dlatego tak łatwo je zignorować na początku projektu.
| Błąd | Skutek | Lepsze podejście |
|---|---|---|
.card .title zamiast klas komponentu |
Zależność od struktury DOM i większa specyficzność | .card__title |
Elementy elementów, np. .card__header__title
|
Trudniej zrozumieć hierarchię i odpowiedzialność | Rozbij komponent albo uprość strukturę |
| Selektory tagów i ID | Trudniejsze nadpisywanie i gorsza reużywalność | Opieraj się na klasach |
| Modyfikator opisujący wygląd zamiast roli | Nazwa starzeje się po zmianie designu | Użyj nazwy opisującej wariant lub stan |
| Zbyt głębokie zagnieżdżanie | Selektory stają się trudne do utrzymania | Ogranicz nesting do sensownych wyjątków |
Jest też druga strona medalu: nie każdy fragment interfejsu musi być rozpisany według najbardziej restrykcyjnej wersji BEM. Jeśli budujesz prosty, jednorazowy układ albo drobny element pomocniczy, czasem wystarczy krótka, jednoznaczna klasa. BEM zaczyna przeszkadzać dopiero wtedy, gdy próbujesz na siłę opisać nim wszystko, także elementy czysto techniczne lub czysto wizualne, które nie mają własnej roli w interfejsie.
Dlatego ja patrzę na tę metodologię pragmatycznie: ma upraszczać pracę zespołu, a nie tworzyć rytuał dla samego rytuału. Jeśli konwencja zaczyna spowalniać decyzje, to zwykle znak, że trzeba ją uprościć, a nie dokładać kolejne reguły.
Jak utrzymać spójność w zespole i projekcie
Najlepszy system nazewnictwa nie przetrwa bez kilku prostych zasad operacyjnych. W praktyce nie potrzeba rozbudowanej dokumentacji, tylko jasnych reguł, które każdy członek zespołu rozumie tak samo.
- Ustal, czym jest blok, element i modyfikator w waszym projekcie, zanim powstanie więcej niż kilka komponentów.
- Przygotuj krótką listę przykładów: jeden dla karty produktu, jeden dla formularza, jeden dla nawigacji.
- Trzymaj klasę bazową razem z modyfikatorem, zamiast zastępować jedną drugą.
- W code review sprawdzaj nie tylko wygląd, ale też to, czy nazwa opisuje rolę, a nie przypadkowy wygląd.
- Jeśli używasz narzędzi typu Stylelint, dodaj reguły ograniczające zbyt głębokie selektory i niespójne nazwy.
W projektach, które rozwijają się długo, naprawdę pomaga też prosty podział odpowiedzialności: jeden wzorzec dla komponentów, osobna warstwa dla helperów i ostrożne podejście do klas stanów. Wtedy nie mieszasz wszystkiego w jednym worku i łatwiej utrzymujesz porządek po kolejnych iteracjach designu.
Jeżeli mam wskazać jedną rzecz, która daje największy zwrot z tej metodologii, to jest nią przewidywalność. Gdy po nazwie klasy od razu wiadomo, czym jest komponent, gdzie kończy się jego struktura i jak działa jego wariant, cały front-end staje się po prostu spokojniejszy w utrzymaniu.