Metodika BEM

Duben 10, 2014
Martin Pešout

Na začátku minulého roku jsem si říkal, že 2013 bude ve znamení optimalizací. Řada firem totiž vytvářela „responsivní“ webové stránky, které šlo zobrazit na mobilních zařízeních, ale ve finále byl uživatel stejně nucen stahovat megabajty dat, aby si mohl výsledný web prohlédnout. Rok poté vidíme, že situace stále není ideální, ale určitá osvěta v tomhle směru už zafungovala. Nicméně objevil se tu ještě jeden problém. Větší poptávka po responsivních webech opět o něco zesložitila vývojářům psaní kaskádových stylů. Minulý rok se tak začalo více hovořit o používání standardů jako jsou OOCSSSMACSS a BEM, které mají za cíl zlepšit strukturu psaní CSS. Ve své praxi se mně zatím nejvíce osvědčila metodika BEM. Proto bych rád tento článek věnoval jejím základům a položil tak úvod pro další zajímavé články do budoucna.

Jak tato metodika vznikla?

Metodika Block Element Modifier, zkráceně BEM, byla poprvé použita ve společnosti Yandex při vývoji robustního interního systému. Na počátku bylo potřeba dosáhnout několika cílů:

  • Najít postup pro rychlý vývoj komponent, které přežijí uvnitř rozrůstajícího se projektu
  • Znovu použitelnost kódu
  • Snadná a rychlá pochopitelnost pro nové členy v týmu

BEM se tak postupně zformovala po několika letech práce na projektu. Výsledkem je poměrně přísný, ale na druhou stranu velice přehledný způsob pojmenovávání CSS tříd. To dělá tuto metodiku ideální pro vývoj projektů, které bude třeba udržovat i několik let.

BEM nepoužívá ID selektory

BEM nepočítá s používáním #ID selektoru v CSS. Já s tímto přístupem naprosto souhlasím a hned vysvětlím proč.

První nevýhodou totiž je, že takovéto elementy není možné znovu použít v kódu. Obečně totiž platí, že na vykreslené HTML stránce musí být každá ID použita pouze jednou. Můžeme sice říct, že naše kaskádové styly se aplikují i v případě, že bude konkrétní ID použito několikrát na stránce. Problém však nastává u JavaScriptu, kde se zohledňuje pouze první výskyt daného ID a dál už se nehledá. To je také důvod, proč použití ID je pro JavaScript rychlejší. Pokud se ale vyhneme tvorbě zbytečně složitých webů, bude tento rozdíl nepatrný.

Druhou větší nevýhodou, je priorita ID selektoru. Důležitější selektor „přebíjí“ méně důležitý. A právě ID selektory mají vyšší prioritu než běžné třídy u HTML elementů. To je taky důvod proč vznikl v CSS zápis !important. Naštěstí všechno, co dokážeme vyjádřit pomocí ID selektoru, můžeme hezky popsat pomocí běžných tříd. Navíc získáme znovupoužitelné komponenty a právě to je pro tuto metodiku podstatná vlastnost.

BLOCK, ELEMENT, MODIFIER

Základem je blok

Jednotlivé části webové stránky lze rozdělit do ucelených komponent - bloků. Jeden blok tak představuje skupinu prvků sdílejících společné vlastnosti. Příkladem může být například hlavička, patička, hlavní menu, produkt, filtr produktů atd. Ukažme si vše na bloku znázorňujícím hlavičku webové stránky, kterou označíme následující třídou.

.header {}

Blok může mít své části

Samotné bloky se můžou skládat z více součástí – elementů. Aby bylo zřejmé, že tyto části patří k naší komponentě, označíme je pomocí vzoru:

.block__element {}

V zápisu používáme k odlišení bloku a elementu dvojí podtržítko. Naše ukázková hlavička může obsahovat např. logo, navigaci, vyhledávání.

.header__logo {}
.header__nav {}
.header__searchbar {}

Specifické elementy

Může se stát, že takto vytvořené bloky a elementy budeme potřebovat ještě v určitých situacích modifikovat. K těmto účelům slouží v BEM takzvané modifikátory. V zápisu používáme k odlišení dvojí pomlčku:

.block--modifier {}
.block__element--modifier {}

Pokud si vezmeme náš ukázkový příklad, může být takovým modifikátorem třeba třída, která z naší navigace udělá navigaci fixní:

.header__nav--sticky {}

Nebo hlavičku roztáhneme na 100% šířky stránky:

.header--fullscreen {}

Jak na zápis v HTML?

Jednotlivé komponenty se můžou dále navzájem prolínat. Náš ukázkový příklad s hlavičkou z předchozího odstavce obohatíme ještě o blok .main-nav, který ponese styly pro hlavní navigaci na webu. Výsledný zápis může vypadat v HTML třeba takto:

<header class="header header--fullscreen">
  <a href="/" class="header__logo"><img src="logo.png" alt="Logo webu" title="Velké logo" /></a>
  <nav class="header__nav main-nav">
    <ul>
      <li class="main-nav__link"><a href="/str1.html">Stránka 1</a></li>
      <li class="main-nav__link main-nav__link--active"><a href="/str2.html">Stránka 2</a></li>
    </ul>
  </nav>
  <form class="header__searchbar" action="process.php">
    <input type="text" name="searchtext" />
    <input type="submit" value="Hledat" />
  </form>
</header>

Závěrem

Pokud jste metodiku BEM ještě nepoužili v praxi, může vám připadat podobný zápis tříd poměrně upovídaný. Ano, názvy tříd jsou o něco delší, nicméně je potřeba se přes to trochu přenést. Až si BEM více osvojíte, tak zjistíte, že vám do vaší práce vnese pořádek a nestane se vám, že byste si začali jednotlivé definice kaskádových stylů mezi sebou omylem přepisovat.

Tags:

8 komentářů. Přidat nový

Dobry den,

jednemu celkom nerozumiem. Ak mam triedu .header__logo a chcem vykreslit logo aj v paticke, tak budem potrebovat triedu .footer__logo a teda budem tuto triedu definovat v CSS 2x? Nie je lepsie mat triedu .logo, ktora sa bude aplikovat na oboch miestach?

Dakujem za odpoved,

Juraj

Odpovědět

Ahoj,

často se stává, že logo v patičce bývá menší. Pak bych využití těchto dvou tříd viděl jako rozumné. Pokud se však jedná v tvém případě o stejné logo a nemáš např. v patičce logo zmenšené nebo jinak upravené, tak klidně můžeš použít třídu .logo

Pokud použiji označení ze článku, bude takové logo vystupovat jako samostatný blok a né jako element (součást jiného bloku). Ničemu to nevadí, protože jednotlivé bloky se můžou prolínat.

Díky ale za připomínku. Snad je to nyní jasnější.

Martin

Odpovědět

Boha, nedávno nás učili pro CSS používat – místo _ a teď tam narvou dvojitej podrtžník?

Odpovědět

Tak v podstatě – a _ můžeš používat stále. Používá se to jako oddělovač jednotlivých slov v názvu třídy. Např. main-menu. Dokonce bych si troufnul říci, že je jedno jestli použiješ pomlčku nebo podtržítko k oddělení slov v třídě (main-menu, main_menu). Mně se ale nejvíce osvědčila pomlčka.

Dvojité podtržítko __ odděluje elementy jednotlivého bloku
Dvojitá pomlčka — odděluje modifikátory bloku

Takže dostáváme něco takového:
.nazev-bloku
.nazev-bloku__element-bloku
.nazev-bloku–modifikator-bloku
.nazev-bloku__element-bloku–modifikator-elementu

Odpovědět

BEM využívám již skoro rok a technika se mi osvědčila. Hlavně spolu s preprocessorem less.
např.


// Entita box
.box {
width:100px;

// Oddělení více boxů od sebe
& + .box {
margin-top: 20px;
}

// Poslední box má ohraničení
&:last-child {
border-bottom: 1px solid black;
}

// Široký box
&--wide {
width: 200px;
}

// Nadpis
&__title {
font-size:200%;
padding:10px;
}
}

Mám jedinou výhradu k dvěma podtržítkám (__) označujícím nějaký subelement. Ve většině fontů a stylů písma splývají do jednoho znaku a oproti dvěma pomlčkám (–) to pak není prostě ono. Zvažuji že budu používat pouze jedno podtržítko. K oddělování slov stejnak používám pouze jednu pomlčku, tak nedojde k nějaké kolizi.

Odpovědět

Naprosto s tebou souhlasím Davide. Stále ale __ používám, i když to skutečně u většiny fontů splývá do sebe.

Já ještě navíc hojně používám Drupal, kde současná verze 7 nepodporuje dvojpodtržítko u názvů tříd. Je to tím, že Drupal 7 vznikl dřív, než se dostala do povědomí metodika BEM. Ale existuje již řada hacků, které použití BEM v Drupal 7 umožní. Kdyby měl s tím někdo v budoucnu problém, tak ať klidně napíše do pošty. Rád pomůžu.

Odpovědět
Jan Pobořil
19.4.2014 18:52

Zmínil jsi, že děláš v Drupalu. Jak se vyrovnáváš se standardním makupem Views, fields a bloků?

Co si myslíš o používání jména tagu ke stylování? Mnoho html5 tagů přímo vybízí k jejich použití místo tříd.

Odpovědět
Martin Pešout
20.4.2014 6:38

Ahoj Honzo,

hlavním problémem v Drupalu 7 je to, že někde převádí podtržítka v názvech tříd na pomlčky. Např. ve Views. Zatím nejlepším řešením, na které jsem narazil, bylo použít následující patch http://goo.gl/bOsfbl který rozšíří mapování tříd při ukládání v ./includes/common.inc

K tvojí druhé otázce. Hojnějšímu používání názvů HTML tagů přímo v CSS bych se předem bránil. Tím, že použiješ v kaskádových stylech konkrétní HTML tagy (např.: .cruise h2), tak nebudeš schopný použít tuto definici na nic jiného. Vždy budeš muset mít tvůj nadpis v <h2>. Ale co když časem zjistíš, že potřebuješ místo <h2> nadpisů používat na stejném místě <h3> nebo se rozhodněš použít obyčejný <div>? Použití tříd nám zajistí větší znovupoužitelnost.

Zastávám ale názor, že určitě né vše v CSS musí být třída. Občas použiji základní tagy ke stylování. Základními tagy myslím třeba <a>. V tomto případě je to podle mě na místě nepoužívat názvy tříd. Pokud v Drupalu nabízíš správcům webu WYSIWYG editor, tak asi nebude třeba přidávat třídy i k <ul>, <li> v textu, který vytvoříš pomocí tohoto editoru. Asi by jsi se těžko vyhnul případným chybám, kde WYSIWYG editor zapomene třídu doplnit. Chce to vždy zvážit, zda vytváříme znovupoužitelné komponenty.

Martin

Odpovědět

Napsat komentář k Jan Pobořil Zrušit odpověď na komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Můžete používat následující HTML značky a atributy: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>