Skip to content

Instantly share code, notes, and snippets.

@zoxon
Created August 5, 2015 10:14
Show Gist options
  • Save zoxon/6e32de9f0e43910a79df to your computer and use it in GitHub Desktop.
Save zoxon/6e32de9f0e43910a79df to your computer and use it in GitHub Desktop.

#b_ BEM CSS методология: Полное руководство

Главное: классы b-someblock__someelement__element__element-modificator - это не BEM! Как правильно верстать по BEM - читайте ниже.

  1. Длинное необязательное вступление
  2. Суть #b_
  • Зачем это всё?
  • Блок
  • Элемент
  • Модификатор
  • Префикс b- и его воображаемые друзья: l-,i-,g- и еретический js-
  • Как менять внешний вид блока: правила модификации
  1. Три главных правила
  2. Ошибки, про которые нигде не написано
  3. Типичные вопросы, ответов на которые вы не нашли на bem.info
  4. Альтернативы или же братья: SMASS, OOCSS, MCSS и BEM.
  5. Семантика в BEM.
  6. BEM и CSS-препроцессоры: Sass и LESS.
  7. Путь Яндекса: кому и зачем нужны bem-tools и прочие "ужасы"
  8. bem-bl и bem-bl в сниппетах от Яндекса (скоро!)
  9. Альтернативные реализации BEM-методологии
  10. Примеры сайтов на BEM
  • Яндекс-сайтов по BEM
  • НЕ-Яндекс-сайтов по BEM
  • Редизайна по BEM
  1. Отзывы: Мнения людей меняется за пару месяцев работы с BEM. Путь к пониманию.
  2. BEM для атеистов - почему это не религия

1. Длинное необязательное вступление

История понимания BEM и зачем он нужен. Можно смело пропустить и читать сразу пункт №2.

— Я не понимал BEM ("что за ерунда придуманная программерами, которые не знают CSS"). Нет не программерами. И не ерунда. — Потом я думал что понимал BEM ("у меня типа независимые стили: специфичность длиной в ширину экрана"). — Потом не знал как же правильно его применять, особенно в рамках веб-студии.

Теперь понимаю и знаю. И хочу рассказать и доказать вам что BEM - единственный правильный вариант организации вёрстки.

  • Да-да, и для небольших студий, у которых не один большой, а множество средних проектов.
  • И для фрилансера с маленькими сайтами.
  • И для лендингов.
  • И даже когда вы делаете правки в чужом спагетти-коде - вы можете (и должны) примерять BEM!

В BEM прекрасно вписываются SMACSS, OOCSS, MCSS. Большинство не знает что такое BEM, или думает, но знает неправильно. Если вы знаете что такое BEM и считаете что он не для вас (или вообще только Яндексу нужен) - дочитайте до конца. Я расскажу вам о том что BEM - это не "xslt, bem-bl, xml, bem-tools, js", а это методология которая решает проблемы с которыми сталкиваемся мы все. Нужная всем. Незаменимая для компаний, значительно ускоряющая скорость и стоимость разработки, поддержки, развития, передачи проекта другим разработчикам, масштабирования. Это прорыв уровня ООП для CSS.

И более того: BEM - семантичен как ничто другое при правильном применении! Поехали, я расскажу вам о тех идеях и логике, что стоят за BEM, и почему и как вы можете его использовать!

Существует огромное кол-во статей, докладов, презентаций про BEM. Почти все - от Яндекса. Я читал все статьи, все доклады по BEM, ездил на субботники, общался с Харисовым, Ткаченко и разработчиками библиотеки bem-bl. Но чтоб понять всё (а не думать что понял) мне потребовалось 5 лет.

Вообще если бы было меньше бредовых статей типа этой: http://habrahabr.ru/post/203440/ которые пишут те, кто сам ничего не понял, было бы лучше. И ошибок было бы меньше.

2. Суть #b_

2.1 Зачем это всё?

Главная проблема вёрстки: каскад.

Зачем был придуман BEM? Чтоб уйти от каскада.

Почему надо уходить от каскада?

Идея убрать каскад кажется дикой - как, это же каскад. У нас каскадные таблицы стилей! Каскад сверху до низу по всей странице! Мы в детстве 2000-х играли в игру "кто напишет меньше тегов"!

Но. У нас страница состоит из блоков. Независимых блоков. Ее части не есть один большой текст, со стилями что спускаются вниз. Это блоки, что могут и должны иметь возможность переноситься.

Разновидности BEM: НБ, АНБ, Лего, текущий BEM, BEM-CSS у "не Яндекса".

Всё это BEM. Разновидности называются "подмножествами BEM".

Что не является BEM.

НЕ BEM:

  • длинные строки каскада ради высокой специфичности селекторов - это не та независимость и ни разу не BEM.
  • базовые стили и их переопределения ниже от_контекста - как общий стиль вёрстки
  • BEM это не только bemjson, bem-tools и прочее. АНБ - тоже BEM

Главные правила BEM.

Чтобы их осознать, мы с вами должны вспомнить как писать правильно. Вспомнить правила. Я говорю "вспомнить", потому что то о чем мы будем говорить - это ручная верстка по BEM. В правильных терминах bem это называется "CSS подмножество BEM". Потому что bem он не только про CSS.

Нам придётся совершить экскурс в историю и пройти путь развития BEM чтобы сформулировать четкие правила "BEM CSS" из общей методилогии. Чтоб собрать все пришлось читать апокрифы. Нет единого стандарта. Есть множество толкований - диалектов BEM. Евангелие от Вегеда, проповедь на внутренней коференции и статьи других апостолов, простите евангелистов BEM. Сам BEM допускает множество вариантов самой методологии. А уж какой путь выбирать в каждом конкретном случае, при модификации кода например - можно спорить и спорить. Поэтому -тот- старый добрый ручной BEM и правду похож на религию.

Сводим всё из разных источников. Очень подробно. Много примеров.

.block

Главное в BEM - понятие независимого блока.

Независимый блок (НБ или просто блок) это самодостаточный элемент страницы, который при перемещении в другое место на странице или на другую страницу не теряет своей самодостаточности. BEM.Клуб на Я.рушке, Независимый блок

Формальное определение

Правила независимости блока:

  1. для описания элемента используется class, но не id
  2. каждый блок имеет префикс
  3. в таблице стилей нет классов вне блоков BEM.Клуб на Я.рушке, История создания BEM (часть первая)

Формальное определение нужно только затем чтоб описать при каких условиях он должен таким стать. Что такое стили вне блоков я опишу ниже.

"Как его таким написать?" Просто писать стили тупо на каждый блок. BEM хорош тем, что позволяет не забивать голову ерундой с каскадом, а сосредоточимся на семантике и логике кода. А с препроцессорами BEM позволяет писать еще и очень чистый и логичный код. Но про это чуть позже.

Как проверить? Просто навести на блок в инспекторе кода. У него не должно быть каскада. Слайд инспектор кода

.block__element

Не бывает элементов вложенных в элементы!

Я тоже раньше так писал:

.form-buy-results__to-city__slider__tab__column_buy

Так делать нельзя.

Как надо?

<div class='block'>
  <div class='block__elem1'>
    <div class='block__elem2'></div>
  </div>
  <div class='block__elem3'></div>
</div>

А в CSS:

.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}

Если вам нужно сделать элемент у элемента, значит вам нужно сделать новый блок! Вместо:

<div class='block'>
    <div class='block__elem1'>
        <div class='block__elem1__elem2'></div>
    </div>
</div>

Надо делать новый блок

<div class='block1'>
    <div class='block2'>
        <div class='block2__elem'></div>
    </div>
</div>

Не пишите странные имена

.block {}
.blockelem1 {}
.blockelem1__elem2 {}

У вас будут проблемы при переносе:

<div class="someblock">
  <div class="blockelem1__elem2"></div>

Бейте на блоки!

Модификатор

Модификаторы в #yandex #b_:

.block-name__elem_key_value

Но для всего мира (csswizardry,cssguidelin,sitepoint) это:

.blockname__elem--mod {}

Синтаксис модификаторов .blockname__elem--mod был запущен в 2012 с легкой руки Nicolas Gallagher @necolas в http://nicolasgallagher.com/about-html-semantics-front-end-architecture/ Причина:

This is merely a naming pattern that I’m finding helpful at the moment. It could take any form. But the benefit lies in removing the ambiguity of class names that rely only on (single) hyphens, or underscores, or camel case. http://nicolasgallagher.com/about-html-semantics-front-end-architecture/

The reason for double rather than single hyphens and underscores is so that your block itself can be hyphen delimited, for example: http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/

Сокращённые модификаторы

Вариацией модификаторов являются "Сокращенные модификаторы" через multiple classes

 <div class="blockName -mod_val"></div>
.blockName {
  &.-mod_val {}
}

Синтаксис с "-", а не с "_", т.к. иначе имя класса будет не валидно.

Стили модификаторов НЕ пишутся без привязки к имени блока То что в Классическом BEM пишется как .block_mod_val {} в сокращенных модификаторах пишут как .block.-mod_val {}

Компании и разработчики, которые используют сокращённые модификаторы:

Проблемы с сокращенными модификаторами:

Сравнение Сокращённых модификаторов и BEViS состояний

...

Абстрактные блоки

Абстрактный блок = блок который является основой других блоков, но сам не существует в верстке без миксования с другми. Тут ещё формальные определения из Ярушки и примеры.

Разница между модификатором и абстрактным блоком

Модификаторы - изменяют или дополняют уже существующий блок. Они нужны тогда когда у вас есть уже готовый блок, который не сильно изменяется и это реализовывается модификаторами. А абстрактные блоки - это кирпичи для ещё не построенного блока, с их помощью можно построить значительно отличающиеся блоки.

Итого - если вам надо:

  • набор похожих блоков - модификаторы
  • набор сходных, но непохожих блоков - абстрактные классы
  • Префикс b- и его воображаемые друзья: l-,i-,g- и еретический js-

А префикс js- (недолго существовавший как с- в #b_) вероятно тоже популяризировал Nicolas Gallagher @necolas в той же статье http://nicolasgallagher.com/about-html-semantics-front-end-architecture/

  • Как менять внешний вид блока: правила модификации

##4. Ошибки, про которые нигде не написано

1. Повторение DOM-дерева

2. Привязка к блоку-родителю

https://twitter.com/delaz/status/580353955244482560

##8. BEM и CSS-препроцессоры: Sass и LESS. Extend-Only Selectors в Sass == абстрактный блок (i-блок) в #b_

%i-block {
  // стили абстрактного блока
}
.b-block {
  @extend %i-block;
}

#Взять примеры ошибок из https://dl.dropboxusercontent.com/u/66873654/%D0%91%D0%AD%D0%9C%D0%BE%D1%81%D0%B8%D0%BF%D0%B5%D0%B4.pdf

#Дополнение из доклада:

##Семантика БЭМ БЭМ всегда ругали за то что он ужасный и «для роботов», а на самом деле он довольно семантичный.

Имена БЭМ-классов создают дополнительный уровень логики.

Есть DOM-дерево, а есть БЭМ-дерево.

Вот обычное DOM-дерево:

<input class="big_red_button order-button">

Раньше мы писали „big-red-button“ (для кнопки покупки) и стало хорошим тоном чтобы название класса отображало не его представление, а его суть, это назвали семантикой, а класс переименовали в например, а „order-button“. Такой код стало легче поддерживать. А БЭМ дополняет это, создавая новый уровень логики, где БЭМ описывает связи между элементами.

Вот БЭМ-дерево:

<input class="order-button b-checkout__submit">

Т.е. обычно имена классов описывают конкретные кусочки, что из себя представляет каждый блок, а БЭМ описывает связи между блоками, положение этого блока в логике документа, это и есть дополнительный уровень семантики.

##Зачем нужен БЭM? БЭМ придумали в Яндексе для решения собственных проблем по поддержке огромного Яндекс-портала. Он был решением проблемы поддерживать html-код легко и быстро. Нам БЭМ нужен т.к он удобен для верстки и позволяет не думать о именах классов, ликивидирует конфликты в коде, код легче расширять. Также благодаря тому что БЭМ это методология — она позволяет легче вводить людей в проекты и заменять их. Нет проблемы ухода сотрудника в отпуск или непонятности его кода.

##БЭМ CSS Ручная верстка по БЭМ называется «BEM CSS». Точнее официльного названия нет, я предлагаю такое. Яндекс предлагает именовтаь его как «CSS подмножество БЭМ», потому что БЭМ он не только про CSS, это огромная методология, вершиной которой является Full Stack BEM с bemjson, bemtools и т.д:

##Full stack BEM? Full stack BEM Когда вам надоесть вручную писать HTML и вам захочется его генерировать и манипулировать им – переходите на Full Stack BEM. Не обязательно полностью отказываться от HTML, можно использовать „BEM project-stub HTML edition“: https://github.com/tadatuta/bem-project-stub-he и https://ru.bem.info/forum/469/

##Пример певерстки по БЭМ Давайте попробуем переверстать «по-БЭМ» такую верстку. Макет: BEM remarkup example Вот так она была сверстана: BEM remarkup example Похоже на БЭМ, но давайте приглядимся, вот так там назначаются стии: BEM remarkup example Тут происходит повышение специфичности, на самом деле это не БЭМ, я написал статью на эту тему.

##Методология Чтобы разобраться как верстать правильно, давайте обратимся к методологии. Проблема непонятости БЭМ в том, что БЭМ рос настолько быстро, что первая крайне сырая документация появилась только спустя 4 года. Яндекс придумал свой шаблонизатор и язык, а мы, простые верстальщики только в прошлом году всерьез задумались о том, что стоит писать код по БЭМ.

Методология не менялась, менялась реализация и от правил по написанию CSS Яндекс дошел до стройной системы. Но нам, чтоб правильно писать код вручную, неободимо вспомнить те самые базовые правила:

##.block .block

Независимый блок

НБ или просто блок, это самодостаточный элемент страницы, который при перемещении в другое место на странице или на другую страницу не теряет своей самодостаточности.

БЭМ.Форум, Независимый блок

Правила независимости блока

  1. для описания элемента используется class, но не id
  2. каждый блок имеет префикс
  3. в таблице стилей нет классов вне блоков

БЭМ.Форум, История создания БЭМ

##Как его таким написать? Просто писать стили тупо на каждый блок. БЭМ хорош тем, что позволяет не забивать голову ерундой с каскадом, а сосредоточимся на семантике и логике кода. А с препроцессорами БЭМ позволяет писать еще и очень чистый и логичный код.

##Как проверить? Просто навести на блок в инспекторе кода. У него не должно быть каскада.

##.block__element .block__element

Элемент

Элемент – это часть блока, отвечающая за отдельную функцию. Он может находиться только в составе блока и не имеет смысла в отрыве от него.

bem.info, Методология

Элемент можно представить себе как папку в файловой системе, это способ организации кода, чтобы было понятно, что к чему относится.

##DOM-дерево

<ul>
  <li>
    <a>
      <span></span>
    </a>
  </li>
</ul>
.ul {}
.ul > li {}
.ul > li > a {}
.ul > li > a > span {}

Вложенные html-элементы - это DOM-дерево. Имена классов, которые вы пишите - это БЭМ-дерево. Почувствуйте разницу!

##БЭМ-дерево

<ul class="menu">
  <li class="menu__item">
    <a class="menu__link">
      <span class="menu__text"></span>
    </a>
  </li>
</ul>
.menu {}
.menu__item {}
.menu__link {}
.menu__text {}

##БЭМ дерево — чистая логика Оно не зависит ни от чего, даже от размещения в документе. БЭМ-дерево не привязано к визуальному представлению блоков, оно отображает только логику, это и есть новый уровень семантики!

##Самая страшная ошибка — .block__el__el__el Так #b_ поняли и используют зарубежом block__el__el

##Я тоже раньше так писал

.form-buy-results__to-city__slider__tab__column_buy

embed/twitter-lehazyo_chatik.html

##Как правильно реализовывать вложенность

<div class="block">
    <div class="block__elem1">
        <div class="block__elem2"></div>
    </div>
    <div class="block__elem3"></div>
</div>
.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}

##Элемент у элемента?

<div class="block">
    <div class="block__elem1">
        <div class="block__elem1__elem2"></div>
    </div>
</div>

Если вам нужно сделать элемент у элемента, значит вам нужно:

  • или создать новый блок
  • или сделать ваше БЭМ-дерево с одинарной вложенностью элементов

##Есть 2 варианта как это переписать 1. Бить на блоки! Делать новый блок

<div class="block1">
    <div class="block2">
        <div class="block2__elem"></div>
    </div>
</div>

2. Рубить ветки! Делать БЭМ-дерево с 1-ой вложенностью элементов

<div class="block1">
    <div class="block1__elem1">
        <div class="block1__elem2"></div>
    </div>
</div>

##Типичная ошибка Попытка вложить имя элемента в имя блока Чтоб «схитрить» и «как-будто не вложить», написать не .block__el1__el2 а .blockel1__el2 или .block__el1el2. Так нельзя. C кодом ниже будут проблемы при переносе:

.block {}
.blockel1 {}
.blockel1__el2 {}

Попытавшись перенести «странный элемент» в другое место - мы получим элемент, что завис «в воздухе» без блока-родителя:

<div class='someblock'>
    <div class='blockel1__el2'></div>
</div>

Так можно делать только если .blockelem сохранит логический смысл при переносе в другой блок.

##element > element нельзя в CSS, но можно в HTML! Обратите внимание - вы не можете вкладывать элементы в элементы в CSS, но можете и должны вкладывать элементы в элементы в HTML! DOM-дерево и БЭМ-дерево могут быть разными.

##Запрет есть исключительно про нейминг!

БЭМ-дерево на то и дерево, что поддерживает вложенность, поэтому в БЭМ-дереве, разумеется, разрешается вкладывать элементы в элементы, блоки в блоки, блоки в элементы.

Vladimir Grinenko, @tadatuta

##Давайте переверстаем наш макет: BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example BEM remarkup example


Сырой html, переписать:

Мы написали BEM-дерево:

<div class="block">
    <div class="block__elem1">
        <div class="block__elem2"></div>
    </div>
    <div class="block__elem3"></div>
</div>
    

Нет каскада:

.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}
    

Модификация

6 видов

  1. Модификатором
    • модификатором блока
    • модификатором элемента
  2. Контекстом (т.е. каскадом от блока выше)
  3. Уровнем переопределения (добавлением-перезаписью файла стилей)
  4. Миксованием (добавлением классов других блоков)
    • включая глобальный класс

Просто добавляйте модификатор!

<div class="block-name__elem_key_value">
    

А для элементов — делай каскад от модификатора.

Модификаторы для элементов, можно?

Если речь идет о простых правках, типа «активный пункт меню», то да, можно:

<a class="menu__link menu__link_state_active">
    

Булевые модификаторы

Кстати в таких простых случаях, можно писать модификаторы просто одним словом:

<a class="menu__link menu__link_active">
    

Но подумайте, может это новый блок?

<iframe src="embed/twitter-bxxx.html" id="twitter-widget-0" scrolling="no" frameborder="0" allowtransparency="true" class="twitter-tweet twitter-tweet-rendered" allowfullscreen="" style="display: block; max-width: 99%; min-width: 220px; padding: 0px; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; margin: 50px auto; border-color: rgb(238, 238, 238) rgb(221, 221, 221) rgb(187, 187, 187); border-width: 1px; border-style: solid; box-shadow: rgba(0, 0, 0, 0.14902) 0px 1px 3px; position: static; visibility: visible; width: 500px;" title="Встроенный твит" height="257"></iframe>

БЭМ допускает ошибки

Самые популярные ошибки

1. block__el__el

Например, слайдеры очень часто верстают дикой вложенностью.

2. Повышение специфичности

В html как-будто всё ok:

<div class="block">
  <div class="block__el">
    

А на деле сели в машину и сгорели:

/* CSS */
.block .block__el {}
    

3. Стили вне блоков

<ul class="menu checkoutForm big myfuckingclass-bold">
    

Почему это ошибки?

Да потому что из-за этого потом тяжелей вносить правки и сложно переместить блок в другое место.

Как мне?...

Вывести текст из WYSIWYG?

Как назначаются стили для типографики? Не будешь же назначать каждому тегу какой-то класс?

Artur Kornakov, @fliptheweb

Добавить .b-text блоку родителю

И использовать каскад.

.b-text h2 {}
.b-text p {}
.b-text img {}
.b-text ul li {}
    

Конечно при большом желании можно настроить визивиг, тот же TinyMCE, чтоб он добавлял нужные имена классов в тегах из визивига.

Задавайте вопросы: ru.bem.info/forum

Пример переверстки по БЭМ (упрощенный)

Диалекты БЭМ

Вот это вот всё на 5 минут:

  • Использование префиксов
  • Альтернативный синтаксис
  • Сокращённые модификаторы
  • JS-блоки

Префиксы

b-, l-, g-, i-, h-, m-, js-

Придумывайте любые правила
Они нужны вам только для пространства имен.

Альтернативный синтаксис и camelCase

Многим нравится зарубежный формат модификаторов, через „--“, он читабельней.

<a class="block-name__element-name--state_active">

Альтернативный синтаксис и camelCase

А через camelCase – ещё читабельней!

<a class="blockName__elementName--state_active">

Сокращенные модификаторы

Сокращенные модификаторы

Правильно писать так:
.block-name__elem_key_value

Или так:
.blockName__elem--key_value

Сокращенные модификаторы

Но некоторых из тех, кто пишет код вручную, такие модификаторы бесят нечитабельностью кода:

<div class="block-name block-name_key1_value1 block-name_key2_value2 block-name_key3_value3">

Сокращенные модификаторы

…и отсутствием дуракоустойчивости:

<div class="block-name_key1_value1 some-another-block">

Сокращенные модификаторы

Им хочется так:

<div class="block-name -key1_value1 -key2_value2 -key3_value3">

Сокращенные модификаторы

<div class="blockName__elem.-key_value">
.blockName {
  &__elem {
    &.-key_value {
    }
  }
}
    

Миксы!
Full BEM Stack!

<style> #warning h2 { position: absolute; top: 300px; left: 150px; font-size: 70px; margin: 0; color: #000; } </style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment