Kompleksowy przewodnik po BEM. Jak pisać piękne CSSy i nie tylko. | DailyWeb.pl

Kompleksowy przewodnik po BEM. Jak pisać piękne CSSy i nie tylko.

Opublikowano 6 miesięcy temu - 2


Zapewne słyszałeś o konwencji nazewnictwa BEM używanej przy tworzeniu stron, serwisów i co ino w sieci. No to mało słyszałeś, bo BEM to coś więcej. Znacznie więcej. W tym artykule postaram się przybliżyć bardziej o co w ogóle w tym wszystkim chodzi.

Słowem wstępu. Wpisując popularne zapytania związane z tą metodologią w wujka google możemy się dowiedzieć że chodzi o to, żeby dobrze nazywać klasy. Niestety ale chciałbym tym artykułem zanegować wiele źródeł, które skupiają się tylko i wyłącznie na tym aspekcie tej metodologii. To jak nazywamy nasze klasy i jak schludny jest nasz kod jest elementem końcowym przygody z BEM.

Krótka nota historyczna. Postaram się na prawdę krótko bo tą informację można znaleźć właściwie wszędzie. Yandex, Rosyjski odpowiednik Google. W Yandexie pracuje wielu developerów, bardzo dobrych developerów. Wymyślają metodologię BEM. Świat kocha BEM. Tutaj cała historia.

Po co stosować BEMa?

Nie wiem czy mogę dodać do stwierdzenia Twórców coś więcej: Metodologia BEM powstała aby tworzyć strony, które powinny być wypuszczone szybko a utrzymywane długo. [BEM] Pomaga tworzyć rozszerzalne i reużywalne komponenty interfejsu. To brzmi jak mokry sen chyba każdego developera. Zrobić szybko, nie wstydzić się, utrzymać łatwo a jak przyjdą nowi to szybko załapią o co chodzi.

Nie tylko CSS.

Tak jak wspomniałem wcześniej metodologia nazewnicza to tylko pewien, w dodatku końcowy element,  który otrzymamy z włączenia myślenia BEMowego. Według mnie właśnie o to chodzi, o to jak myśleć. Bem to pewnego rodzaju sposób postrzegania projektu, tego jak on działa, jego architektury. Dzieje się to na wielu płaszczyznach.

Strona internetowa to nie jeden wielki monolit który projektujemy i kodujemy z góry do dołu jak leci. Jest to zbiór pewnych komponentów, które występują na stronie z reguły wiele razy. Polecam używanie BEMa nawet do niewielkich projektów jak prosta wizytówka bo to wygodne, zwłaszcza jak po czasie do projektu trzeba wrócić. Jednak cała potęga myślenia BEMowego tkwi w troszkę bardziej skomplikowanych stronach niż zwykłe wizytówki ;)

Block

Gdy patrzymy na stronę i przyjmiemy założenie że mamy ją utrzymać prostą głupcze [KISS] oraz suchą [DRY] zaczniemy ją dzielić na coraz mniejsze elementy składowe. Te elementy muszą same w sobie być spójne, mieć sens, być niezależne i działać wszędzie w obrębie naszego serwisu. Jeśli je przeniesiemy gdzie indziej dalej będą spełniały swoją funkcję i będą działały tak jak to sobie zaplanowaliśmy. To są właśnie bloki, pierwsza część nazwy BlockEM.

Element

Przyjmijmy dla zobrazowania sytuacji że naszym blokiem, który jest prosty i chcemy aby występował w kilku miejscach jest menu nawigacyjne. Dla  tego przykładu niech będzie to jednopoziomowe nieskomplikowane menu. Nasz blok menu możemy przenieść na każdą podstronę, będzie on działał wszędzie tak samo, będzie spełniał to samo zadanie. Jednak przytoczony blok menu składa się jeszcze z innych elementów - linków nawigacyjnych, które pozwalają nam się poruszać po stronie. Te elementy naszego bloku to właśnie.... Elementy. Druga część BlockElementM.

Modifier

Nasze menu wszędzie jest takie samo, fajnie, mamy komponent(blok), który jest reużywalny, niezależny i nie powoduje tego, że musimy się powtarzać. Jednak do naszego menu chcemy dodać posypkę w postaci lepszego designu. Podstrona na której aktualnie jesteśmy niech w menu będzie reprezentowana poprzez podkreślenie. Bardzo często stosowany schemat. No więc nasz blok menu ma swoje elementy którymi są linki do poszczególnych podstron. Jeden z tych linków wyróżnimy poprzez podkreślenie. Mówiąc inaczej zmodyfikujemy go. Modyfikator to trzecia część naszej układanki zwanej BlockElementModifier.

Póki co nic nie jest związane z konwencją nazewnictwa. Jeszcze chwilę nie będzie ale obiecuję, że do tego też dojdziemy.

Takie spojrzenie na stronę internetową czy też serwis jest bardzo dobre nie tylko od strony technicznej. Dobry design też kieruje się takimi samymi zasadami. KISS i DRY powinny występować wszędzie, życie byłoby prostsze. Jeśli chodzi o design to konkretnie mam na myśli świetną metodologię nazywaną Atomowym designem.

W dużym skrócie projekt serwisu tworzymy ze stron, które składają się z szablonów. Tutaj wchodzi natura. Szablony składają się z organizmów, te zaś z molekuł. Najmniejszą jednostką w tym podejściu do projektowania jest zaś atom, z którego tworzymy wszystko. Jestem pewien że bez problemu możecie tutaj znaleźć odniesienie Atomic Design <->BEM. Jeśli kogoś zainteresowała ta metodologia projektowania i jej nie znał dotychczas to odsyłam do drugiego rozdziału książki jej twórcy który wyjaśnia wszystko w szczegółach.

Ze swojego doświadczenia wiem, że ta korelacja pomiędzy Atomic Designem a BEMem OGROMNIE upraszcza coś co zwykło kuleć - komunikację między projektantem a developerem. Połączenie tego w całość daje świetne efekty, zwłaszcza jeśli pracujemy nad jakimś swoim frameworkiem.

Myśląc w BEMie operujemy na pewnym poziomie abstrakcji, która ułatwia nam wiele rzeczy ponieważ przestają nas dotyczyć ograniczenia technologiczne. Zaczynamy widzieć projekt strony jako coś złożonego z bloczków, wiemy do czego dane puzzle służą i jak to wszystko podzielić. Które bloki będą używane w innych miejscach. Dzięki takiemu podejściu w bardzo prosty sposób możemy utrzymać nasz projekt ponieważ wymiana poszczególnego bloku na nowy bądź inny nie będzie większym problemem. Przecież są niezależne. Jednocześnie wprowadzając dodatkowe zmiany możemy łatwo zdecydować czy chcemy je wprowadzić we wszystkich wystąpieniach danego bloku w serwisie czy rozszerzyć o jakiś modyfikator i spowodować inne zachowanie tylko w jednym miejscu.

Mając już tak uporządkowaną wizję serwisu aż żal jej nie przelać również  na strukturę plików. Mówiąc prościej: blok = katalog. Wracając do naszego przykładu menu. Wszystkie pliki potrzebne do prawidłowego działania naszego bloku menu powinny znaleźć się w jednym folderze. Partial HTMLowy, plik CSS/SCSS, pliki JavaScriptu jeśli są wymagane do prawidłowego działania bloku a czasami nawet więcej. Co to może być to "więcej"? A no w przypadku bardziej skomplikowanych projektów czy też frameworków możemy trzymać chociażby dokumentację czy też pliki graficzne. Przechowywanie dużych plików graficznych w repozytorium to już jest osobny dość obszerny temat... Jednak dokumentacja może nam się później fajnie budować a jednocześnie będzie zarówno prosta w utrzymaniu (aktualizujemy przy wprowadzaniu zmian w folderze) jak i czytaniu (jeśli ktoś będzie miał styczność z komponentami po raz pierwszy wyjaśnienie ma podane na tacy, sami też odczujemy tego benefit jeśli będziemy musieli wrócić do czegoś, co robiliśmy pół roku temu).

P.S. Dalej nie ruszyliśmy tematu konwencji nazewnictwa więc może już pora to uczynić :)

Nazywanie selektorów

Główną ideą stojącą za konwencją nazewnictwa w BEM jest utrzymanie nazw selektorów CSS w jak najprostszej formie, jednocześnie jak najbardziej wymownych, dokładnie opisujących co to jest. Trzymanie się tych zasad pozwala uczynić development oraz debugowanie o wiele prostszymi.

Czytelniejszy kod to lepszy kod. Wracając kolejny raz do naszego przykładu menu. Mamy selektor menuitemactive patrząc na tą nazwę po pierwsze ciężko ją rozczytać. Dodajmy więc jakieś separatory. Metod jakie używać do rozdzielania wyrazów jest sporo ale uważam, że używanie jakiejkolwiek podniesie jakość kodu wielokrotnie. menu-item-active czytelniej prawda? Patrząc na to poprzez pryzmat tego co wcześniej przeczytałeś możemy to sobie rozkodować na blok menu, w nim jakiś element item i jego modyfikator - stan active. To jest oczywiście prosty przykład, w rzeczywistości napotkamy o wiele bardziej skomplikowane. Poznajmy teraz podstawową i chyba najczęściej używaną konwencję budowania nazw.

Konwencja nazewnictwa selektorów CSS.

  • nazwy jednostek składowych (tak nazywają się ogólnie bloki, elementy, modyfikatory) tworzymy używając cyfr oraz mały liter z alfabetu łacińskiego. Zalecam po angielsku ;)
  • Jeśli dana jednostka musi zawierać więcej słów aby była dobrze opisana łączymy je przy pomocy myślnika "-" na przykład blok bottom-menu lub modyfikator is-disabled

Do łączenia ze sobą jednostek używamy najczęściej "blok__element--modyfikator" czyli na naszym przykładzie będzie to: bottom-menu__menu-item--is-disabled. To już troszeczkę dłuższy przykład ale pokazuje o co chodzi. Pokazuje także jaka siła drzemie w dobrze opisanym selektorze - patrząc w kod wiemy od razu co zmieniamy.

Należy jednak pamiętać, że trzymając się BEMa nie ma możliwości łączenia ze sobą bloków ani elementów wewnątrz bloku. Takie praktyki doprowadzą do ograniczania nas podczas późniejszych modyfikacji kodu oraz znacznie go skomplikują. Czyli unikamy czegoś takiego: bottom-menu-header-menu bottom-menu__menu-item__menu-icon

Jeśli natomiast chodzi o modyfikatory to mogą one występować bezpośrednio w bloku np bottom-menu--hidden jak również w elemencie. Modyfikatory nie powinny występować poza obszarem swojego rodzica/jednostki. Modyfikatory posiadają jeszcze jedną przydatną funkcję - wartości. Wygląda to tak jakbyśmy do jednej jednostki dodawali wiele modyfikatorów. Tutaj już bardziej zaawansowany przykład muszę przytoczyć. Załóżmy, że nasze dolne menu jest wykorzystywane w jakimś frameworku. Chcielibyśmy mieć możliwość używania jakiś tematów/szablonów kolorystycznych. Tworzymy to poprzez modyfikator dla bloku: bottom-menu--theme ale wiemy, że tych szablonów może być wiele, będzie to w takim razie jakaś wartość naszego modyfikatora, mówiąca o tym, jaki konkretnie szablon aplikujemy: bottom-menu--theme--light bądź bottom-menu--theme--dark. To jest już kwestia osoby tworzącej portal ponieważ można to także rozwiązać poprzez wielowyrazową nazwę modyfikatora, bez używania wartości: bottom-menu--theme-dark jednak różnice użycia będą nieznacznie wpływały na to jak będziemy pisać kod.

Oto przykład troszkę bardziej skomplikowanego menu:

Z czasem mogą nam powstawać coraz dłuższe nazwy selektorów czy klas. To jest niestety efekt uboczny mocno niezagważdżanych komponentów w takiej sytuacji możemy na przykład stworzyć nowego taga z selektora, na naszym przykładzie stworzylibyśmy sobie tagi <menubar></menubar><menu></menu>.  Możemy zagnieżdżać bloki w innych blokach i elementach więc musimy dobrze przemyśleć sobie strukturę jak to wszystko sobie poorganizować. To jest też według mnie kolejny z plusów BEMa - wymusza na nas dobre przemyślenie i zaplanowanie całej strony co później jest tylko i wyłącznie na plus.

Nie ma chyba złotego środka, który powie Ci jak nazywać zawsze dobrze swoje selektory. Rób to z głową, niech ich nazwa jest adekwatna do tego co robią - wtedy będzie znacznie prościej. Niestety ale musisz kilka razy zapędzić się w kozi róg, który zablokuje Ci przyjazne nazwy po to abyś następnym razem to lepiej przemyślał.

Według mnie BEM to jedna z lepszych metodologii ponieważ tak naprawdę nie chodzi w niej o te całe nazwy. Znaczy chodzi, ale nie tylko, co z resztą już wiesz skoro tutaj dobrnąłeś. BEM daje nam możliwość spojrzenia na stronę w sposób, który pozwoli nam ją napisać szybciej i łatwiej a i utrzymanie po czasie będzie prostsze. W większych projektach to jest bardzo użyteczne bo pozwala na sporą redukcję kodu oraz prostą skalowalność. Nie można też zignorować korelacji do Atomic Designu, to świetnie ze sobą gra jeśli mamy dobry Visual Language przygotowany, wydaje mi się nawet że połączenie tych dwóch elementów niweluje znaczną ilość konfliktów i nieporozumień na linii Developer<->Designer

Najczęściej przy doradzaniu używania BEMa spotykam się z niechęcią spowodowaną pisaniem niby to nadmiarowych nazw klas / selektorów. To minie, jestem pewien bo jednocześnie te same osoby po nawet dość krótkim czasie zauważają plusy BEMa i jednak go lubią i same polecają dalej.

To jednak jeszcze nie wszystko.. macki metodologii BEM sięgają o wiele dalej niż tylko do HTMLa czy CSSa. Yandex stworzył jeszcze coś takiego jak BEMJSON, zasady używania JSa oraz tego jak go pisać w projekcie, jak tworzyć buildy oraz wiele innych które możecie znaleźć na stronie projektu oraz głębiej w sieci, ja nie czuję się na siłach aby przekazywać tą wiedzę.

Powyższy artykuł to troszkę dłuższe rozwinięcie już istniejącego materiału w naszym archiwum ;) Jeśli masz coś do dodania - z chęcią posłucham, chciałbym aby ten tutorial był jak najbardziej dokładny i przydatny.

Źródła którymi się podpierałem podczas pisania:

BEM przede wszystkim

BEM 101 CSSTricks

CSS Wizardy

Smashing

Get Bem

P.S. Jeśli interesują Cię inne metodologie możesz pogooglać za OOCSS, ACSS, SMACSS, SUIT CSS czy Systematic CSS