BEM dla początkujących: dlaczego potrzebujesz BEM

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Izolacja stylów CSS jest najczęstszym punktem startowym stosowania BEM. Ale to najmniej, co może Ci dać BEM. BEM wprowadza systemowe podejście do Twojego projektu i utrzymuje go z dala od bałaganu.

BEM sprawia, że ​​Twój kod jest skalowalny i wielokrotnego użytku, zwiększając w ten sposób produktywność i ułatwiając pracę zespołową. Nawet jeśli jesteś jedynym członkiem zespołu, BEM może Ci się przydać. Niemniej jednak wielu programistów uważa, że ​​takie podejście systemowe, jak BEM, nakłada dodatkowe ograniczenia na ich projekt i sprawia, że ​​projekt jest przeciążony, nieporęczny i powolny.

Zbierzemy wszystkie główne aspekty BEM w skondensowanej formie. Ten artykuł pomoże Ci zrozumieć podstawowe idee BEM w zaledwie 20 minut i odrzucić uprzedzenia, że ​​podejście systemowe jest szkodliwe dla Twojego projektu.

Big BEM składa się z metodologii , technologii , bibliotek i narzędzi . W tym artykule porozmawiamy więcej o samej metodologii, ponieważ jest to skoncentrowane doświadczenie ogromnej liczby programistów i zapewnia systematyczne podejście do każdego projektu.

Aby pokazać kilka praktycznych przypadków BEM, omówimy technologie BEM i całkowicie pominiemy biblioteki i narzędzia.

Od teorii do praktyki:

  • Główne powody, dla których nie używamy żadnych selektorów poza klasami
  • Podstawy BEM
    • Bloki i elementy
    • Modyfikatory i miksy
    • Bloki w strukturze pliku
  • Nieoczywiste zalety metodologii
  • Praktyczny przypadek: BEM to nie tylko CSS
  • BEM to konfigurowalny system

Czy BEM jest bohaterem czy złoczyńcą? To zależy od Ciebie! Ale najpierw przeczytaj artykuł.

BEM jako logo Batmana
BEMBatman
Więcej po skoku! Kontynuuj czytanie poniżej ↓

Główne powody, dla których nie używamy żadnych selektorów poza klasami

Jedną z podstawowych zasad metodologii BEM jest używanie wyłącznie selektorów klas. W tej sekcji wyjaśnimy dlaczego.

  • Dlaczego nie używamy identyfikatorów?
  • Dlaczego nie używamy selektorów tagów?
  • Dlaczego nie używamy uniwersalnego selektora?
  • Dlaczego nie używamy resetowania CSS?
  • Dlaczego nie używamy selektorów zagnieżdżonych?
  • Dlaczego nie połączymy tagu i klasy w selektorze?
  • Dlaczego nie używamy selektorów kombinowanych-
  • Dlaczego nie używamy selektorów atrybutów?

Nie używamy identyfikatorów (selektory identyfikatorów)

Identyfikator zapewnia unikalną nazwę elementu HTML. Jeśli nazwa jest unikatowa, nie możesz jej ponownie użyć w interfejsie. Uniemożliwia to ponowne użycie kodu.

Wspólne nieporozumienia

  1. Identyfikatory są wymagane do korzystania z JavaScript.
    Nowoczesne przeglądarki mogą pracować z identyfikatorami lub klasami. Każdy rodzaj selektora jest przetwarzany w przeglądarce z taką samą szybkością.
  2. Identyfikatory są używane z tagiem <label> .
    Jeśli umieścisz <label> wewnątrz kontrolki, nie potrzebujesz identyfikatora. Zamiast <input id="ID"><label for="ID">Text</label> po prostu użyj <label><input type="...">Text</label> .

Nie używamy selektorów tagów

Znaczniki strony HTML są niestabilne: nowy projekt może zmienić zagnieżdżenie sekcji, poziomy nagłówków (na przykład z <h1> na <h3> ) lub zamienić akapit <p> w znacznik <div> . Każda z tych zmian zepsuje style, które są napisane dla tagów. Nawet jeśli projekt się nie zmienia, zestaw tagów jest ograniczony. Aby użyć istniejącego układu w innym projekcie, musisz rozwiązać konflikty między stylami napisanymi dla tych samych znaczników.

Rozszerzony zestaw znaczników semantycznych również nie spełnia wszystkich wymagań dotyczących układu.

Przykładem jest sytuacja, gdy nagłówek strony zawiera logo. Kliknięcie na logo otwiera stronę główną serwisu ( index ). Możesz oznaczyć go tagami, używając tagu <img> dla obrazu i tagu <a> dla linku.

 <header> <a href="/"> <img src="img.logo.png" alt="Logo"> </a> </header>

Aby odróżnić link do logo od zwykłego linku w tekście, potrzebujesz dodatkowych stylów. Teraz usuń podkreślenie i niebieski kolor z linku do logo:

 header a { ... }

Link do logo nie musi być wyświetlany na stronie głównej, więc zmień znaczniki strony indeksu:

 <header> <!-- the <a> tag is replaced with <span> --> <span> <img src="img.logo.png" alt="Logo"> </span> </header>

Nie musisz usuwać podkreślenia i niebieskiego koloru znacznika <span> . Ustalmy więc ogólne zasady dotyczące linku do logo z różnych stron:

 header a, header span { ... }

Na pierwszy rzut oka ten kod wydaje się w porządku, ale wyobraź sobie, że projektant usunie logo z układu. Nazwy selektorów nie pomagają zrozumieć, które style należy usunąć z projektu z logo. Selektor „nagłówek a” nie pokazuje związku między linkiem a logo. Selektor ten może należeć do linku w menu nagłówka lub na przykład do linku do profilu autora. Selektor „rozpiętości nagłówka” może należeć do dowolnej części nagłówka.

Aby uniknąć nieporozumień, po prostu użyj selektora klasy logo , aby napisać style logo:

 .logo { ... }

Nie używamy resetowania CSS

Reset CSS to zestaw globalnych reguł CSS stworzonych dla całej strony. Te style wpływają na wszystkie węzły układu, naruszają niezależność komponentów i utrudniają ich ponowne użycie.

W BEM „resetuj” i „normalizuj” nie są nawet używane dla pojedynczego bloku. Resetowanie i normalizacja anulują istniejące style i zastępują je innymi stylami, które w każdym przypadku będziesz musiał zmienić i zaktualizować później. W rezultacie programista musi napisać style, które zastępują te, które właśnie zostały zresetowane.

Nie używamy uniwersalnego selektora ( * )

Selektor uniwersalny wskazuje, że projekt zawiera styl, który wpływa na wszystkie węzły w układzie. Ogranicza to ponowne wykorzystanie układu w innych projektach:

  • Do projektu trzeba dodatkowo przenieść style z gwiazdką. Ale w tym przypadku uniwersalny selektor może wpłynąć na style w nowym projekcie.
  • Do przenoszonego układu należy dodać style z gwiazdką.

Ponadto uniwersalny selektor może sprawić, że kod projektu będzie nieprzewidywalny. Na przykład może wpływać na style komponentów biblioteki uniwersalnej.

Popularne style nie oszczędzają czasu. Często programiści zaczynają od zresetowania wszystkich marginesów dla komponentów ( * { margin: 0; padding: 0; } ), ale potem nadal ustawiają je tak samo jak w układzie (np. margin: 12px; padding: 30px; ).

Nie używamy zagnieżdżonych selektorów

Zagnieżdżone selektory zwiększają sprzęganie kodu i utrudniają ponowne użycie kodu.

Metodologia BEM nie zabrania selektorów zagnieżdżonych, ale zaleca, aby nie używać ich zbyt często. Na przykład zagnieżdżanie jest odpowiednie, jeśli trzeba zmienić style elementów w zależności od stanu bloku lub przypisanego mu motywu.

 .button_hovered .button__text { text-decoration: underline; } .button_theme_islands .button__text { line-height: 1.5; }

Nie używamy selektorów połączonych

Selektory połączone są bardziej szczegółowe niż selektory pojedyncze, co utrudnia przedefiniowanie bloków.

Rozważ następujący kod:

 <button class="button button_theme_islands">...</button>

Załóżmy, że ustawiłeś reguły CSS w selektorze .button.button_theme_islands , aby mniej pisać. Następnie dodajesz do bloku modyfikator „aktywny”:

 <button class="button button_theme_islands button_active">...</button>

Selektor .button_active nie redefiniuje właściwości bloku zapisanych jako .button.button_theme_islands , ponieważ .button.button_theme_islands jest bardziej szczegółowe niż .button_active . Aby go przedefiniować, połącz selektor modyfikatora bloku z selektorem .button i zadeklaruj go poniżej .button.button_theme_islands , ponieważ oba selektory są równie specyficzne:

 .button.button_theme_islands {} .button.button_active {}

Jeśli używasz prostych selektorów klas, nie będziesz miał problemów z przedefiniowaniem stylów:

 .button_theme_islands {} .button_active {} .button {}

Nie łączymy tagu i klasy w selektorze

Łączenie tagu i klasy w tym samym selektorze (na przykład button.button ) sprawia, że ​​reguły CSS są bardziej szczegółowe, więc ich przedefiniowanie jest trudniejsze.

Rozważ następujący kod:

 <button class="button">...</button>

Załóżmy, że ustawiasz reguły CSS w selektorze button.button . Następnie dodajesz active modyfikator do bloku:

 <button class="button button_active">...</button>

Selektor .button_active nie redefiniuje właściwości bloku napisanych jako button.button , ponieważ button.button jest bardziej szczegółowy niż .button_active . Aby było to bardziej szczegółowe, należy połączyć selektor modyfikatora bloku ze znacznikiem button.button_active .

W miarę rozwoju projektu możesz otrzymać bloki z input.button , span.button lub a.button . W takim przypadku wszystkie modyfikatory bloku button i wszystkie jego zagnieżdżone elementy będą wymagały czterech różnych deklaracji dla każdego wystąpienia.

Możliwe wyjątki

W rzadkich przypadkach metodologia pozwala na łączenie selektorów tagów i klas. Na przykład można to wykorzystać do ustawienia stylu komentarzy w systemach CMS, które nie mogą wygenerować prawidłowego układu.

Możesz użyć komentarza, aby napisać tekst, wstawić obrazy lub dodać znacznik. Aby dopasować je do projektu witryny, programista może wstępnie zdefiniować style dla wszystkich tagów dostępnych dla użytkownika i kaskadowo przenieść je do zagnieżdżonych bloków:

 <div class="content"> ... <!-- the user's text --> </div> CSS rules: .content a { ... } .content p { font-family: Arial, sans-serif; text-align: center; }

Nie używamy selektorów atrybutów

Selektory atrybutów zawierają mniej informacji niż selektory klas. Jako dowód rozważmy przykład z formularzem wyszukiwania w nagłówku:

 <header> <form action="/"> <input name="s"> <input type="submit"> </form> </header>

Spróbuj użyć atrybutów selektora do napisania stylów formularza:

 header input[type=submit], header input[type=checkbox] { width: auto; margin-right: 20px; } header input[type=checkbox] { margin: 0; }

W tym przykładzie nie można stwierdzić na pewno na podstawie nazwy selektora, że ​​style należą do formularza wyszukiwania. Korzystanie z klas sprawia, że ​​jest to bardziej zrozumiałe. Zajęcia nie mają ograniczeń, które uniemożliwiają czytelne pisanie. Na przykład możesz napisać to tak:

 .form .search { ... }

Teraz kod jest mniej niejednoznaczny i jasne jest, że style należą do formularza wyszukiwania.

Ale zagnieżdżone selektory nadal uszczegóławiają reguły CSS i uniemożliwiają przenoszenie układu między projektami. Aby pozbyć się zagnieżdżania, skorzystaj z zasad BEM.

Podsumowanie : class jest jedynym selektorem, który pozwala wyizolować style każdego komponentu w projekcie; zwiększyć czytelność kodu i nie ograniczać ponownego wykorzystania układu.

Izolacja stylów CSS to najczęstszy punkt początkowy podróży z BEM. Ale to najmniej, co może Ci dać BEM. Aby zrozumieć, jak wyodrębnione, niezależne komponenty są rozmieszczone w BEM, musisz poznać podstawowe pojęcia, tj. Blok, Element, Modyfikator i Mieszanie. Zróbmy to w następnej sekcji.

Podstawy BEM

  • Bloki i elementy
  • Modyfikatory i miksy
  • Bloki w strukturze pliku

Blok i elementy

Metodologia BEM to zbiór uniwersalnych reguł, które można zastosować niezależnie od stosowanych technologii, takich jak CSS, Sass, HTML, JavaScript czy React.

BEM pomaga rozwiązać następujące zadania:

  • Użyj ponownie układu;
  • Bezpiecznie przenoś fragmenty układu w obrębie projektu;
  • Przenieś gotowy układ między projektami;
  • Twórz stabilny, przewidywalny i przejrzysty kod;
  • Skróć czas debugowania projektu.

W projekcie BEM interfejs składa się z bloków, które mogą zawierać elementy. Bloki są niezależnymi komponentami strony. Element nie może istnieć poza blokiem, więc pamiętaj, że każdy element może należeć tylko do jednego bloku.

Pierwsze dwie litery w BEM oznaczają zamki B i elementy E. Nazwa bloku jest zawsze unikalna. Ustawia przestrzeń nazw dla elementów i zapewnia widoczne połączenie między częściami bloku. Nazwy bloków są długie, ale jasne, aby pokazać połączenie między komponentami i uniknąć utraty jakichkolwiek części tych komponentów podczas przenoszenia układu.

Aby zobaczyć pełną moc nazewnictwa BEM, rozważ ten przykład z formularzem. Zgodnie z metodologią BEM formularz implementowany jest za pomocą bloku form . W języku HTML nazwa bloku jest zawarta w atrybucie class :

 <form class="form" action="/">

Wszystkie części formularza (blok form ), które same w sobie nie mają sensu, są uważane za jego elementy. Tak więc pole wyszukiwania ( search ) i przycisk ( submit ) są elementami bloku form . Klasy wskazują również, że element należy do bloku:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

Zauważ, że nazwa bloku jest oddzielona od nazwy elementu specjalnym separatorem. W klasycznym schemacie nazewnictwa BEM dwa znaki podkreślenia są używane jako separator. Wszystko może działać jako separator. Istnieją alternatywne konwencje nazewnictwa, a każdy programista wybiera tę, która mu odpowiada. Ważne jest to, że separatory pozwalają programowo odróżnić bloki od elementów i modyfikatorów.

Nazwy selektorów wyjaśniają, że aby przenieść formularz do innego projektu, musisz skopiować wszystkie jego komponenty:

 .form__search {} .form__submit {}

Używanie bloków i elementów do nazw klas rozwiązuje ważny problem: pomaga nam pozbyć się zagnieżdżonych selektorów. Wszystkie selektory w projekcie BEM mają tę samą wagę. Oznacza to, że znacznie łatwiej jest przedefiniować style pisane zgodnie z BEM. Teraz, aby użyć tego samego formularza w innym projekcie, wystarczy skopiować jego układ i style.

Idea nazewnictwa komponentów BEM polega na tym, że można jednoznacznie zdefiniować połączenie między blokiem a jego elementami.

Modyfikatory i miksy

Oficjalnie „ M ” oznacza modyfikator, ale oznacza również jeszcze jedno ważne pojęcie w BEM: „mix”. Zarówno modyfikatory, jak i miksery wprowadzają zmiany w bloku i jego elementach. Przyjrzyjmy się temu bliżej.

Modyfikatory

Modyfikator definiuje wygląd, stan i zachowanie bloku lub elementu. Dodawanie modyfikatorów jest opcjonalne. Modyfikatory pozwalają łączyć różne funkcje bloków, ponieważ można użyć dowolnej liczby modyfikatorów. Ale blokowi lub elementowi nie można przypisać różnych wartości tego samego modyfikatora.

Przyjrzyjmy się, jak działają modyfikatory.

Wyobraź sobie, że projekt wymaga tego samego formularza wyszukiwania, co w powyższym przykładzie. Powinien mieć te same funkcje, ale wyglądać inaczej (np. formularze wyszukiwania w nagłówku i w stopce strony powinny się różnić). Pierwszą rzeczą, jaką możesz zrobić, aby zmienić wygląd formularza, jest napisanie dodatkowych stylów:

 header .form {} footer .form {}

Selektor header .form ma większą wagę niż selektor form , co oznacza, że ​​jedna reguła zastąpi drugą. Ale jak już wspomnieliśmy, selektory zagnieżdżone zwiększają sprzęganie kodu i utrudniają ponowne użycie, więc to podejście nie działa dla nas.

W BEM możesz użyć modyfikatora, aby dodać nowe style do bloku:

 <!-- Added the form_type_original modifier--> <form class="form form_type_original" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

Wiersz <form class="form form_type_original"></form> wskazuje, że blokowi przypisano modyfikator type z original wartością. W klasycznym schemacie nazwa modyfikatora jest oddzielona od nazwy bloku lub elementu podkreśleniem.

Formularz może mieć niepowtarzalny kolor, rozmiar, typ lub motyw projektu. Wszystkie te parametry można ustawić za pomocą modyfikatora:

 <form class="form form_type_original form_size_m form_theme_forest"> <form class="form form_type_original form_size_m form_theme_forest">

Ta sama forma może wyglądać inaczej, ale pozostać w tym samym rozmiarze:

 <form class="form form_type_original form_size_m form_theme_forest"></form> <form class="form form_type_original form_size_m form_theme_sun"></form>

Ale selektory dla każdego modyfikatora nadal będą miały tę samą wagę:

 .form_type_original {} .form_size_m {} .form_theme_forest {}

Ważne : modyfikator zawiera tylko dodatkowe style, które w jakiś sposób zmieniają oryginalną implementację bloku. Pozwala to na ustawienie wyglądu bloku uniwersalnego tylko raz i dodanie do stylów modyfikatora tylko tych funkcji, które różnią się od oryginalnego kodu bloku.

 .form { /* universal block styles */ } .form_type_original { /* added styles */ }

Dlatego modyfikator powinien zawsze znajdować się w tym samym węźle DOM co blok i element, z którym jest powiązany.

 <form class="form form_type_original"></form>

Możesz użyć modyfikatorów, aby zastosować uniwersalne komponenty w bardzo specyficznych przypadkach. Kod bloku i elementu nie ulega zmianie. Niezbędna kombinacja modyfikatorów jest tworzona w węźle DOM.

Mieszanki

Mieszanka umożliwia zastosowanie tego samego formatowania do różnych elementów HTML oraz łączenie zachowania i stylów kilku jednostek, unikając jednocześnie powielania kodu. Mogą zastąpić abstrakcyjne bloki opakowujące.

Mieszanka oznacza, że ​​hostujesz kilka encji BEM (bloków, elementów, modyfikatorów) w jednym węźle DOM. Podobnie jak modyfikatory, miksy służą do zmiany bloków. Spójrzmy na kilka przykładów, kiedy powinieneś użyć mieszanki.

Bloki mogą różnić się nie tylko wizualnie, ale także semantycznie. Na przykład formularz wyszukiwania, formularz rejestracyjny i formularz zamawiania ciast to wszystkie formularze. W układzie są zaimplementowane z blokiem „forma”, ale nie mają wspólnych stylów. Nie da się poradzić sobie z takimi różnicami za pomocą modyfikatora. Możesz zdefiniować wspólne style dla takich bloków, ale nie będziesz mógł ponownie użyć kodu.

 .form, .search, .register { ... }

Możesz użyć miksera, aby utworzyć semantycznie różne bloki dla tej samej formy:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

Selektor klasy .form opisuje wszystkie style, które można zastosować do dowolnego formularza (zamówienia, wyszukiwania lub rejestracji):

 .form {}

Teraz możesz zrobić formularz wyszukiwania z formularza uniwersalnego. Aby to zrobić, utwórz w projekcie dodatkową klasę search . Ta klasa będzie odpowiedzialna tylko za wyszukiwanie. Aby połączyć style i zachowanie klas .form i .search , umieść te klasy w jednym węźle DOM:

 <form class="form search" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

W tym przypadku klasa .search jest oddzielnym blokiem, który definiuje zachowanie. Ten blok nie może mieć modyfikatorów odpowiedzialnych za formę, motywy i rozmiary. Te modyfikatory należą już do formy uniwersalnej. Mieszanka pomaga łączyć style i zachowanie tych bloków.

Weźmy jeszcze jeden przykład, w którym zmienia się semantyka składnika. Oto menu nawigacyjne w nagłówku strony, w którym wszystkie wpisy są linkami:

 <nav class="menu"> <a class="link" href=""></a> <a class="link" href=""></a> <a class="link" href=""></a> </nav>

Funkcjonalność linków jest już zaimplementowana w bloku link , ale linki menu muszą różnić się wizualnie od linków w tekście. Istnieje kilka sposobów zmiany łączy menu:

  1. Utwórz modyfikator wpisu menu, który zamienia wpis w łącze:
     <nav class="menu"> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> </nav>

    W takim przypadku, aby zaimplementować modyfikator, należy skopiować zachowanie i style bloku `link`. Doprowadzi to do duplikacji kodu.
  2. Użyj połączenia uniwersalnego bloku `link` i elementu `item` bloku `menu`:
     <nav class="menu"> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> </nav>

    Dzięki połączeniu dwóch encji BEM można teraz zaimplementować podstawową funkcjonalność łącza z bloku `link` i dodatkowe reguły CSS z bloku `menu` i uniknąć duplikacji kodu.

Geometria zewnętrzna i pozycjonowanie: rezygnacja z abstrakcyjnych opakowań HTML

Miksery służą do pozycjonowania bloku względem innych bloków lub do pozycjonowania elementów wewnątrz bloku. W BEM style odpowiedzialne za geometrię i pozycjonowanie ustawiane są w bloku nadrzędnym. Weźmy uniwersalny blok menu, który należy umieścić w nagłówku. W układzie blok musi mieć wcięcie 20px od bloku nadrzędnego.

To zadanie ma kilka rozwiązań:

  1. Napisz style z wcięciami dla bloku menu:
     .menu { margin-left: 20px; }

    W tym przypadku blok „menu” nie jest już uniwersalny. Jeśli musisz umieścić menu w stopce strony, będziesz musiał edytować style, ponieważ wcięcia prawdopodobnie będą inne.
  2. Utwórz modyfikator bloku menu:
     <div> <ul class="menu menu_type_header"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
     .menu_type_header { margin-left: 20px; } .menu_type_footer { margin-left: 30px; }

    W tym przypadku projekt będzie zawierał dwa rodzaje menu, choć tak nie jest. Menu pozostaje takie samo.
  3. Zdefiniuj zewnętrzne położenie bloku: zagnieżdż blok `menu` w abstrakcyjnym opakowaniu (na przykład blok `wrap`) ustawiając wszystkie wcięcia:
     <div class="wrap"> <ul class="menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

    Aby uniknąć pokusy tworzenia modyfikatorów i zmiany stylów bloków w celu umieszczenia bloku na stronie, musisz zrozumieć jedną rzecz:

    Wcięcie z bloku nadrzędnego nie jest cechą bloku zagnieżdżonego. Jest to cecha bloku nadrzędnego. Musi wiedzieć, że zagnieżdżony blok musi być wcięty od granicy o określoną liczbę pikseli.
  4. Użyj mieszanki. Informacje o rozmieszczeniu bloku zagnieżdżonego są zawarte w elementach bloku nadrzędnego. Następnie nadrzędny element bloku jest mieszany z zagnieżdżonym blokiem. W takim przypadku zagnieżdżony blok nie określa żadnych wcięć i można go łatwo ponownie wykorzystać w dowolnym miejscu.

Przejdźmy do naszego przykładu:

 <div> <ul class="menu header__menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

W tym przypadku zewnętrzna geometria i położenie bloku menu są ustawiane przez element header__menu . Blok menu nie określa żadnych wcięć i można go łatwo ponownie wykorzystać.

Element nadrzędny bloku (w naszym przypadku jest to header__menu ) wykonuje zadanie opakowujących bloków odpowiedzialnych za zewnętrzne pozycjonowanie bloku.

Bloki w strukturze pliku

Wszystkie projekty BEM mają podobną strukturę plików. Znajoma struktura plików ułatwia programistom poruszanie się po projekcie, przełączanie się między projektami i przenoszenie bloków z jednego projektu do drugiego.

Implementacja każdego bloku jest przechowywana w osobnym folderze projektu. Każda technologia (CSS, JavaScript, testy, szablony, dokumentacja, obrazy) znajduje się w osobnym pliku.

Na przykład, jeśli wygląd bloku input jest ustawiony za pomocą CSS, kod jest zapisywany w pliku input.css .

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript

Kod dla modyfikatorów i elementów jest również przechowywany w osobnych plikach bloku. Takie podejście pozwala na uwzględnienie w kompilacji tylko tych modyfikatorów i elementów, które są niezbędne do wykonania bloku.

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript input_theme_sun.css # The "input_theme_sun" modifier implementation input__clear.css # The "input__clear" element implementation with CSS input__clear.js # The "input__clear" element implementation with JavaScript

Aby usprawnić nawigację po projekcie, połącz modyfikatory bloków z wieloma wartościami w katalogach.

Struktura plików każdego projektu BEM składa się z poziomów redefinicji (więcej o nich możesz dowiedzieć się tutaj). Poziomy redefinicji pozwalają na:

  • Podziel projekt na platformy;
  • Łatwa aktualizacja bibliotek bloków zawartych w projekcie;
  • Używaj wspólnych bloków do tworzenia wielu projektów;
  • Zmień motywy projektu bez wpływu na logikę projektu;
  • Przeprowadzaj eksperymenty w projekcie na żywo.

Używanie bloków i przechowywanie wszystkich technologii blokowych w tym samym folderze ułatwia przenoszenie bloków między projektami. Aby przenieść wszystkie style i zachowanie bloku razem z układem, po prostu skopiuj folder bloku do nowego projektu.

Nieoczywiste zalety metodologii

Wygoda równoległego rozwoju

W BEM dowolny układ jest podzielony na bloki. Ponieważ bloki są niezależne, mogą być rozwijane równolegle przez kilku programistów.

Deweloper tworzy blok jako uniwersalny komponent, który można ponownie wykorzystać w dowolnym innym projekcie.

Przykładem jest biblioteka bloków bem-components, która zawiera uniwersalne bloki, takie jak łącze, przycisk i pole wejściowe. Łatwiej jest tworzyć bardziej złożone bloki z uniwersalnych komponentów. Na przykład selektor lub pole wyboru.

Wykorzystanie bloków w układzie projektu pozwala zaoszczędzić czas na integrowanie kodu napisanego przez kilku programistów, gwarantuje niepowtarzalność nazw komponentów i pozwala testować bloki na etapie rozwoju.

Testowanie układu

Testowanie funkcjonalności całej strony jest problematyczne, zwłaszcza w dynamicznym projekcie połączonym z bazą danych.

W BEM każdy blok jest objęty testami. Testy to technologia implementacji blokowej, taka jak Javascript lub CSS. Bloki są testowane na etapie rozwoju. Łatwiej jest sprawdzić poprawność jednego bloku, a następnie złożyć projekt z przetestowanych bloków. Następnie wszystko, co musisz zrobić, to upewnić się, że opakowanie bloku działa poprawnie.

Konfigurowalna kompilacja projektu

Dla wygodnego programowania wszystkie bloki i technologie w projekcie BEM są umieszczone w osobnych folderach i plikach. Aby połączyć pliki źródłowe w jeden plik (na przykład, aby umieścić wszystkie pliki CSS w project.css , wszystkie pliki JS w project.js itd.), używamy procesu budowania.

Kompilacja wykonuje następujące zadania:

  • Łączy pliki źródłowe, które są rozłożone w systemie plików projektu;
  • Zawiera tylko niezbędne bloki, elementy i modyfikatory (elementy BEM) w projekcie;
  • Postępuje zgodnie z kolejnością włączania podmiotów;
  • Przetwarza kod pliku źródłowego podczas budowania (np. kompiluje kod LESS do kodu CSS).

Aby uwzględnić w kompilacji tylko niezbędne encje BEM, musisz utworzyć listę bloków, elementów i modyfikatorów używanych na stronach. Ta lista nazywa się deklaracją .

Ponieważ bloki BEM są rozwijane niezależnie i umieszczane w osobnych plikach w systemie plików, nie „wiedzą” nic o sobie nawzajem. Aby zbudować bloki oparte na innych blokach, określ zależności. Odpowiada za to technologia BEM: pliki deps.js Pliki zależności informują silnik kompilacji, które dodatkowe bloki muszą zostać uwzględnione w projekcie.

Praktyczny przypadek: BEM to nie tylko CSS

W poprzednich sekcjach wszystkie przykłady kodu dotyczą CSS. Ale BEM pozwala modyfikować zachowanie bloku i jego reprezentację w HTML w taki sam sposób, jak w CSS.

Jak korzystać z szablonów w BEM

W języku HTML znaczniki bloku są powtarzane za każdym razem, gdy blok pojawia się na stronie. Jeśli tworzysz znacznik HTML ręcznie, a następnie musisz naprawić błąd lub wprowadzić zmiany, będziesz musiał zmodyfikować znacznik dla każdego wystąpienia bloku. Aby wygenerować kod HTML i automatycznie zastosować poprawki, BEM używa szablonów; bloki odpowiadają za sposób ich prezentacji w HTML.

Szablony umożliwiają:

  • Skróć czas potrzebny na debugowanie projektu, ponieważ zmiany szablonu są automatycznie stosowane do wszystkich bloków projektu;
  • Zmodyfikuj układ bloków;
  • Przenieś bloki z bieżącym układem do innego projektu.

BEM używa silnika szablonów bem-xjst, który zawiera dwa silniki:

  • BEMHTML
    Przekształca opis strony w formacie BEMJSON na kod HTML. Szablony są opisane w plikach .bemhtml.js.
  • BEMTREE
    Przekształca dane do BEMJSON. Szablony są opisane w formacie BEMJSON w plikach .bemtree.js.

Jeśli szablony nie są napisane dla bloków, mechanizm szablonów domyślnie ustawia znacznik <div> dla bloków.

Porównaj deklarację bloków i wynik HTML:

Deklaracja:

 { block: 'menu', content: [ { elem: 'item', content: { block: 'link'} }, { elem: 'item', elemMods: { current: true }, // Set the modifier for the menu item content: { block: 'link' } } ] }

HTML:

 <div class="menu"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div>

Aby zmodyfikować układ bloku menu , musisz napisać szablony dla bloku:

  1. Zmieńmy tag bloku menu :
     block('menu')( tag()('menu') // Set the "menu" tag for the menu block )

    Zmodyfikowany kod HTML:
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </menu>

    Podobnie jak w CSS, szablon jest stosowany do wszystkich bloków „menu” na stronie.
  2. Dodaj dodatkowy element ( menu__inner ), który działa jako opakowanie wewnętrzne i odpowiada za układ elementów w bloku menu . Pierwotnie element menu__inner nie był zawarty w deklaracji, więc musimy go dodać podczas budowania szablonów.

    Szablony BEM są napisane w JavaScript, więc możesz również użyć JavaScript, aby dodać nowy element do szablonu:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content }; }) )
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__inner"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div> </menu>
  3. Zastąp tagi dla wszystkich elementów inner i item :
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) )
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <div class="link"></div> </li> <li class="menu__item menu__item_current"> <div class="link"></div> </li> </ul> </menu>
  4. Ustaw tag <a> dla wszystkich linków na stronie:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) ); block('link')( tag()('a') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <a class="link"></a> </li> <li class="menu__item menu__item_current"> <a class="link"></a> </li> </ul> </menu>
  5. Zmodyfikuj istniejący szablon. Reguły w szablonach są stosowane w taki sam sposób, jak w CSS: niższa reguła zastępuje wyższą regułę. Dodaj nowe reguły do ​​szablonu i zmień tag linku z <a> na <span> :
     block('link')( tag()('a') ); block('link')( tag()('span') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <span class="link"></span> </li> <li class="menu__item menu__item_current"> <span class="link"></span> </li> </ul> </menu>

BEM to konfigurowalny system

Metodologia BEM zapewnia ścisłe zasady tworzenia systemu w Twoim projekcie. Ale jednocześnie można dostosować wiele reguł BEM. Metodologia BEM pozwala zmienić konwencję nazewnictwa, wybrać najbardziej dogodną strukturę plików lub dodać do bloku dowolne technologie.

Teraz możesz dostroić się do systemu i stworzyć własnego superbohatera BEM!

BEM jako logo Kapitana Ameryki
BEM Kapitan Ameryka

Jak uzyskać więcej z BEM?

Aby rozpocząć naukę zasad BEM, odwiedź naszą stronę internetową. Jeśli masz jakieś pytania, które chciałbyś zadać zespołowi, dołącz do naszego kanału Telegram lub otwórz dyskusję na naszym Forum BEM.