#b_ BEM CSS методология: Полное руководство
Главное: классы b-someblock__someelement__element__element-modificator - это не BEM! Как правильно верстать по BEM - читайте ниже.
История понимания BEM и зачем он нужен. Можно смело пропустить и читать сразу пункт №2.
— Я не понимал BEM ("что за ерунда придуманная программерами, которые не знают CSS"). Нет не программерами. И не ерунда. — Потом я думал что понимал 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/ которые пишут те, кто сам ничего не понял, было бы лучше. И ошибок было бы меньше.
Зачем был придуман BEM? Чтоб уйти от каскада.
Идея убрать каскад кажется дикой - как, это же каскад. У нас каскадные таблицы стилей! Каскад сверху до низу по всей странице! Мы в детстве 2000-х играли в игру "кто напишет меньше тегов"!
Но. У нас страница состоит из блоков. Независимых блоков. Ее части не есть один большой текст, со стилями что спускаются вниз. Это блоки, что могут и должны иметь возможность переноситься.
Всё это BEM. Разновидности называются "подмножествами BEM".
НЕ BEM:
Чтобы их осознать, мы с вами должны вспомнить как писать правильно. Вспомнить правила. Я говорю "вспомнить", потому что то о чем мы будем говорить - это ручная верстка по BEM. В правильных терминах bem это называется "CSS подмножество BEM". Потому что bem он не только про CSS.
Нам придётся совершить экскурс в историю и пройти путь развития BEM чтобы сформулировать четкие правила "BEM CSS" из общей методилогии. Чтоб собрать все пришлось читать апокрифы. Нет единого стандарта. Есть множество толкований - диалектов BEM. Евангелие от Вегеда, проповедь на внутренней коференции и статьи других апостолов, простите евангелистов BEM. Сам BEM допускает множество вариантов самой методологии. А уж какой путь выбирать в каждом конкретном случае, при модификации кода например - можно спорить и спорить. Поэтому -тот- старый добрый ручной BEM и правду похож на религию.
Сводим всё из разных источников. Очень подробно. Много примеров.
Главное в BEM - понятие независимого блока.
Независимый блок (НБ или просто блок) это самодостаточный элемент страницы, который при перемещении в другое место на странице или на другую страницу не теряет своей самодостаточности. BEM.Клуб на Я.рушке, Независимый блок
Формальное определение
Правила независимости блока:
- для описания элемента используется class, но не id
- каждый блок имеет префикс
- в таблице стилей нет классов вне блоков BEM.Клуб на Я.рушке, История создания BEM (часть первая)
Формальное определение нужно только затем чтоб описать при каких условиях он должен таким стать. Что такое стили вне блоков я опишу ниже.
"Как его таким написать?" Просто писать стили тупо на каждый блок. BEM хорош тем, что позволяет не забивать голову ерундой с каскадом, а сосредоточимся на семантике и логике кода. А с препроцессорами BEM позволяет писать еще и очень чистый и логичный код. Но про это чуть позже.
Как проверить? Просто навести на блок в инспекторе кода. У него не должно быть каскада. Слайд инспектор кода
Не бывает элементов вложенных в элементы!
Я тоже раньше так писал:
.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 {}
Компании и разработчики, которые используют сокращённые модификаторы:
Проблемы с сокращенными модификаторами:
...
Абстрактный блок = блок который является основой других блоков, но сам не существует в верстке без миксования с другми. Тут ещё формальные определения из Ярушки и примеры.
Модификаторы - изменяют или дополняют уже существующий блок. Они нужны тогда когда у вас есть уже готовый блок, который не сильно изменяется и это реализовывается модификаторами. А абстрактные блоки - это кирпичи для ещё не построенного блока, с их помощью можно построить значительно отличающиеся блоки.
Итого - если вам надо:
А префикс js- (недолго существовавший как с- в #b_) вероятно тоже популяризировал Nicolas Gallagher @necolas в той же статье http://nicolasgallagher.com/about-html-semantics-front-end-architecture/
##4. Ошибки, про которые нигде не написано
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? Когда вам надоесть вручную писать HTML и вам захочется его генерировать и манипулировать им – переходите на Full Stack BEM. Не обязательно полностью отказываться от HTML, можно использовать „BEM project-stub HTML edition“: https://github.com/tadatuta/bem-project-stub-he и https://ru.bem.info/forum/469/
##Пример певерстки по БЭМ Давайте попробуем переверстать «по-БЭМ» такую верстку. Макет: Вот так она была сверстана: Похоже на БЭМ, но давайте приглядимся, вот так там назначаются стии: Тут происходит повышение специфичности, на самом деле это не БЭМ, я написал статью на эту тему.
##Методология Чтобы разобраться как верстать правильно, давайте обратимся к методологии. Проблема непонятости БЭМ в том, что БЭМ рос настолько быстро, что первая крайне сырая документация появилась только спустя 4 года. Яндекс придумал свой шаблонизатор и язык, а мы, простые верстальщики только в прошлом году всерьез задумались о том, что стоит писать код по БЭМ.
Методология не менялась, менялась реализация и от правил по написанию CSS Яндекс дошел до стройной системы. Но нам, чтоб правильно писать код вручную, неободимо вспомнить те самые базовые правила:
##.block
Независимый блок
НБ или просто блок, это самодостаточный элемент страницы, который при перемещении в другое место на странице или на другую страницу не теряет своей самодостаточности.
БЭМ.Форум, Независимый блок
Правила независимости блока
- для описания элемента используется class, но не id
- каждый блок имеет префикс
- в таблице стилей нет классов вне блоков
БЭМ.Форум, История создания БЭМ
##Как его таким написать? Просто писать стили тупо на каждый блок. БЭМ хорош тем, что позволяет не забивать голову ерундой с каскадом, а сосредоточимся на семантике и логике кода. А с препроцессорами БЭМ позволяет писать еще и очень чистый и логичный код.
##Как проверить? Просто навести на блок в инспекторе кода. У него не должно быть каскада.
##.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_ поняли и используют зарубежом
##Я тоже раньше так писал
.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
##Давайте переверстаем наш макет:
Сырой 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-name__elem_key_value">
А для элементов — делай каскад от модификатора.
Если речь идет о простых правках, типа «активный пункт меню», то да, можно:
<a class="menu__link menu__link_state_active">
Кстати в таких простых случаях, можно писать модификаторы просто одним словом:
<a class="menu__link menu__link_active">
Например, слайдеры очень часто верстают дикой вложенностью.
В html как-будто всё ok:
<div class="block">
<div class="block__el">
А на деле сели в машину и сгорели:
/* CSS */
.block .block__el {}
<ul class="menu checkoutForm big myfuckingclass-bold">
Да потому что из-за этого потом тяжелей вносить правки и сложно переместить блок в другое место.
Artur Kornakov, @flipthewebКак назначаются стили для типографики? Не будешь же назначать каждому тегу какой-то класс?
.b-text
блоку родителюИ использовать каскад.
.b-text h2 {}
.b-text p {}
.b-text img {}
.b-text ul li {}
Конечно при большом желании можно настроить визивиг, тот же TinyMCE, чтоб он добавлял нужные имена классов в тегах из визивига.
b-
,
l-
,
g-
,
i-
,
h-
,
m-
,
js-
…
Придумывайте любые правила
Они нужны вам только для пространства имен.
Многим нравится зарубежный формат модификаторов, через „--“, он читабельней.
<a class="block-name__element-name--state_active">
А через 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 {
}
}
}