- PVSM.RU - https://www.pvsm.ru -
На Хабре уже много писали о методологии БЭМ, выросшей в Яндексе. И мы решили, что пора системно рассказать о том, откуда она появилась и что сделало БЭМ таким, каким мы его знаем. Думаем, это будет интересно не только тем, кто уже использует БЭМ, но и тем, кто считает, что эта методология не подходит для их проектов. Возможно, они увидят, что мы решали проблемы, похожие на их собственные, и найдут что-то полезное для себя.
Конечно, все началось с собственных потребностей Яндекса. Вместе с тем, как он рос, росло и количество сотрудников, которые занимаются фронтендом. Постепенно команда увеличилась настолько, что стало очевидно — без единых стандартов работать будет сложно. К тому же, мы находимся в офисах Яндекса в разных городах. Возникла идея создать общую методологию, которая поможет организовать процессы в большой команде, работающей над разными проектами. А главное то, что мы хотели не только упорядочить и ускорить разработку, но и снизить порог входа в проект для нового разработчика.
Какие требования мы сформулировали:
Мы стремились к тому, чтобы с увеличением числа разработчиков улучшалось и качество продукта. Это значит, что разработчики должны быть в курсе работы друг друга и не изобретать заново то, что уже реализовано. Мы хотели создать единую команду, которая работает над разными проектами.
Но когда все начиналось, ни о каких компонентных подходах и модульности в веб-разработке речи не шло. Все верстали сайты, складывая CSS в один файл project.css
, скрипты, которых было очень мало, — в project.js
, а картинки — в папку images
.
В 2005 году обычный, с точки зрения интерфейса, проект был набором статических HTML-страниц. Вот такой была типичная структура проекта того времени:
about.html # Для каждой страницы создавался отдельный HTML-файл
index.html
…
project.css # Стили находились в одном файле для всего проекта
project.js # Скрипты хранились в одном файле для всего проекта
images/ # Картинки складывались в отдельную директорию
yandex.png
В CSS использовались id
, классы и теги.
Пример
#foot div div div div
{
background-position: 54%;
background-image: url(../i/foot-4.png);
}
Типичный CSS того времени в большинстве случаев содержал длинный каскад.
Малейшие изменения требовали длительного рефакторинга. Свёрстанные статические HTML-страницы нарезались в шаблоны. Если HTML изменялся, все правки было необходимо переносить вручную в шаблон.
Вёрстка в больших проектах была неуправляемой.
Технологии (HTML, CSS, JavaScript), которые мы использовали, изменялись в зависимости от требований проекта, а принципы БЭМ должны были быть универсальны.
Мы сформулировали основные правила, по которым будут жить и развиваться наши проекты, и которые никак не будут зависеть от технологий и инструментов.
Чтобы ускорить разработку, необходимо было облегчить поддержку HTML и CSS отдельных компонентов страницы, сделать код менее связанным. Для этого мы разбили страницу на части. Так появилось новое понятие — блок [1]. Блок мог состоять из различных элементов [2], которые не использовались вне самого блока. Состояния и поведение блока и элемента можно было задавать с помощью модификатора [3].
Это были три ключевых понятия, на которых основывалось большинство правил. Аббревиатура от трех слов Блок, Элемент и Модификатор стала названием методологии — БЭМ.
Логически и функционально независимый компонент страницы. Блок полностью самодостаточен: у него может быть свое поведение, шаблоны, стили, документация и не только. Блоки могут использоваться в любом месте страницы, повторно, даже в другом проекте.
Одни блоки можно вкладывать в другие, компоновать, использовать для создания более сложных блоков.
Часть блока, которая не может использоваться в отрыве от него и имеет смысл только в рамках своего родителя. Элементы могут быть обязательными и опциональными.
Работая с элементами, важно помнить правило: не рекомендуется создавать элементы элементов. Если вложить один элемент в другой, будет невозможно изменить внутреннюю структуру блока: элементы нельзя будет поменять местами, удалить или добавить без корректировки существующего кода.
Свойство блока или элемента, которое меняет их внешний вид, состояние или поведение.
Модификатор имеет имя и может иметь значение. Использование модификаторов опционально. У блока/элемента может быть несколько разных модификаторов одновременно.
Так, например, с помощью модификатора можно изменить не только цвет меча, но и его функциональность (как показано в случае с красным мечом):
Все принципы БЭМ формировались и внедрялись постепенно. Мы начали с того, что сформулировали жесткие правила именования CSS-селекторов.
По БЭМ-методологии блоки не уникальны и их всегда можно использовать повторно, поэтому в описании CSS-правил отказались от использования id
.
Блок не должен зависеть от окружающих его блоков и сам не должен влиять на соседние блоки, поэтому в CSS отказались от:
Важной определяющей сущностью в именовании селекторов стал блок:
-
).__
). Модификатор — одним (_
).Мы долго экспериментировали с префиксами в именах, но в итоге отказались от них.
Пример
header
.header__search-form
— элемент search-form
блока header
.header_theme_green-forest
— модификатор theme
в значении green-forest
блока header
.header__search-form_disabled
— булев модификатор disabled
элемента search-form
блока header
.HTML
<div class="header header_theme_green-forest">...</div>
CSS
.header { color: red; }
Существует ряд альтернативных схем именования [4]. Выбор всегда остается за вами.
Но мы рекомендуем придерживаться описанной выше схемы, так как инструменты БЭМ-платформы умеют работать именно с данным вариантом именования.
Мы хотели упорядочить HTML и в итоге пришли к тому, что больше не пишем HTML руками. Подробнее читайте в разделе про описание инструментов БЭМ [5].
В HTML каждая БЭМ-сущность определяется своим классом.
<div class="block-name">
<div class="block-name__elem"></div>
...
</div>
В простейшем случае блок соответствует DOM-узлу, один к одному. Но DOM-узел и блок — это не всегда одно и то же. На одном DOM-узле может совмещаться несколько сущностей. Это называется миксом [6].
С помощью миксов можно:
Пример
В проекте кнопки реализованы блоком button
. Необходимо поместить кнопку в форму поиска (search-form
) и задать для кнопки отступы. Для этого воспользуемся миксом блока button
и элемента button
блока search-form
:
<div class="search-form">
<div class="button search-form__button"></div>
</div>
Микс позволяет использовать универсальную кнопку, которая ничего не знает об отступах от границ конкретной формы. В данном случае в форме поиска есть элемент search-form__button
, который знает, где ему надо находиться, и блок button
, который нужно отображать.
Вместо микса можно создать дополнительный модификатор блоку button
, но мы не рекомендуем этот способ, так как позиционирование блока button
по смыслу не является частью универсального блока, а подходит только для его конкретного места использования.
Нас не устраивала первоначальная структура проекта в файловой системе: в ней было сложно ориентироваться и находить нужные технологии сущностей.
Что мы хотели получить от новой структуры:
Сначала мы попробовали разделить репозиторий проекта по технологиям:
css/
html/
js/
xml/
xsl/
Такой подход не показал кардинальных изменений. Поэтому мы вынесли общую часть кода, подходящую для всех проектов и платформ, в отдельную директорию common
. Специфические реализации, необходимые только определённым проектам, складывали отдельно — в директорию service
. А примеры — в директорию example
.
common/
css/
js/
xml/
xsl/
example/
html/
service/
auto/
css/
xml/
Так мы быстрее находили нужный код для отдельных проектов. Но эта структура всё равно не отвечала всем нашим требованиям.
Чтобы создать нужную нам структуру проекта и реализовать наши цели, которые мы перед собой ставили, мы вывели на передний план блоки, а не технологии.
Блок в файловой системе полностью независим: все технологии, необходимые для его реализации, находятся в директории этого блока.
Ускорения разработки
Ускорение рефакторинга
Универсальная расширяемая система
Придумали новый термин — технология реализации.
Блоки могут выполнять разные функции на странице. В зависимости от предназначения блока может меняться его реализация. Под реализацией в БЭМ понимают поведение, внешний вид, шаблоны, документацию к блоку, все виды тестов, картинки и так далее.
Для реализации блока используются различные технологии, например:
Выбор технологий реализации не ограничен, разве только требованиями вашего проекта.
В новой организации файловой структуры каждая технология реализации представляет собой отдельный файл с соответствующим расширением. Все файлы реализации блока хранятся в директории этого блока.
Всё в проекте перестраивается относительно этого нового принципа. Блок становится ключевым понятием БЭМ. Соответственно, изменяется и структура файловой системы.
Пример
blocks/
input/ # Директория блока input
_theme/ # Директория опционального модификатора theme
input_theme_forest.css # Реализация модификатора theme в значении forest в технологии CSS
__clear/ # Директория опционального элемента clear
input__clear.css # Реализация элемента clear в технологии CSS
input__clear.png # Реализация элемента clear в технологии PNG
input.css # Блок input в технологии CSS
input.js # Блок input в технологии JavaScript
button/ # Директория блока button
button.css
button.js
button.png
Уровнем переопределения мы стали называть директории с реализацией блоков. Появление уровней позволило изменять реализацию блока, добавляя новые свойства (доопределять) или изменяя старые (переопределять) на другом уровне. Конечная реализация блока собирается со всех уровней последовательно.
Уровни переопределения позволяют:
Если сравнить уровни со слоями, то базовый слой – это исходная реализация блока, а каждый последующий слой накладывается сверху и дополняет (наследует) или изменяет базовую реализацию.
Пример
project/ # Уровень проекта
input/ # Измененная реализация блока input
button/
header/
library-blocks/ # Уровень библиотеки
input/ # Базовая реализация блока input
button/
popup/
Как вы могли заметить, наша команда тоже начинала работу с БЭМ постепенно. Гибкость БЭМ-методологии позволяет настраивать её под ваши текущие процессы.
Не существует универсального метода, чтобы начать применять методологию в своем проекте. Каждая конкретная команда встраивает его в процесс разработки и использует так, как ей удобно.
Например, у вас есть проект, в котором вы хотите применить БЭМ только для вёрстки. Вы используете в проекте CSS и HTML, значит можно начать с правил именования CSS-селекторов. Это самый распространенный способ использования БЭМ-методологии. Многие команды начинают именно с него. Мы тоже с этого начинали.
По мере внедрения новых правил возникает потребность в собственных инструментах и технологиях.
В веб-разработке финальный продукт состоит из разных технологий (например, HTML, CSS, JavaScript). Основной принцип БЭМ-методологии — использовать единые термины и подходы к реализации во всех применяемых технологиях.
Чтобы работать в БЭМ-терминах и писать декларативно JavaScript, который можно разделять по уровням переопределения, нам понадобился собственный фреймворк — i-bem [9].
Типичная веб-разработка сводилась к тому, что мы писали HTML, затем нарезали его на шаблоны. При изменении дизайна приходилось менять HTML и шаблоны вручную.
Чтобы избавиться от ручной работы, мы добавили новый уровень абстракции — БЭМ-дерево, которое позволяет работать со структурой веб-страницы в терминах блоков, элементов и модификаторов. БЭМ-дерево — это абстракция над DOM-деревом.
БЭМ-дерево описывает все БЭМ-сущности, которые используются на странице, их состояния, порядок, вложенность. Оно может быть выражено любым форматом, который поддерживает древовидную структуру, например, XML или JSON.
Пример
Рассмотрим пример DOM-дерева:
<header class="header">
<img class="logo">
<form class="search-form">
<input type="input">
<button type="button"></button>
</form>
<div class="lang-switcher"></div>
</header>
Ему соответствует такое БЭМ-дерево:
header
logo
search-form
input
button
lang-switcher
Его можно сравнить с шаблонизатором Jade [10], но отличие в том, что мы пишем не HTML, а используем абстракции.
Это же БЭМ-дерево будет иметь следующий вид в форматах XML и BEMJSON:
XML
<block:header>
<block:logo/>
<block:search-form>
<block:input/>
<block:button/>
</block:search-form>
<block:lang-switcher/>
</block:header>
BEMJSON [11] — JavaScript-формат, который позволяет работать в БЭМ-терминах. BEMJSON позволяет абстрагироваться от HTML-разметки и описывать страницу в терминах блоков, элементов и модификаторов.
{
block: 'header',
content : [
{ block : 'logo' },
{
block : 'search-form',
content : [
{ block : 'input' },
{ block : 'button' }
]
},
{ block : 'lang-switcher' }
]
}
Мы описываем страницу, которую хотим получить в браузере в виде БЭМ-дерева и не пишем HTML руками: шаблонизатор BEMHTML [12] обрабатывает BEMJSON и генерируют HTML.
Чтобы работать со всеми технологиями в удобном для разработчика виде, мы разделили проект на множество отдельных файлов. Это дало нам описанные выше преимущества. Но нам понадобилась сборка [13] и оптимизация, чтобы созданный код мог работать в браузере.
Собирать все файлы вручную неудобно, мы начинаем автоматизировать большинство повторяющихся процессов. Появляются bem-tools [14] — набор инструментов для работы с файлами по БЭМ-методологии. Позже на смену bem-tools пришел ENB [15].
Чтобы иметь возможность собрать разрозненные файлы, ничего не знающие друг о друге, используется технология DEPS [16], которая указывает зависимости одного блока от другого или от набора блоков.
Инструменты БЭМ направлены на то, чтоб разработчик писал код так, как ему удобно, а оптимизацией и подключением в проект только нужных файлов в правильном порядке занимались роботы.
Многие БЭМ-библиотеки можно найти в open source. Базовыми являются:
i-bem
и 20 блоков-хелперов для разработки по БЭМ-методологии.Библиотеку bem-components можно подключать по аналогии с Bootstrap: добавить предварительно собранные файлы библиотеки и вставить их в HTML страницы с помощью элементов <link>
и <script>
.
<link rel="stylesheet" href="https://yastatic.net/bem-components/latest/desktop/bem-components.css">
<script src="https://yastatic.net/bem-components/latest/desktop/bem-components.js+bemhtml.js"></script>
Такой способ поставки называется Dist [19] и включает предсобранный CSS- и JavaScript-код и шаблоны. С ним вам не потребуется инструменты для сборки или шаблонизаторы — блоки заранее собраны и работают.
О том, как подключать файлы с CDN или локально, использовать bower или самостоятельно собрать файлы библиотеки из исходников, читайте в описании библиотеки [20].
Быстро начать разработку БЭМ-проекта можно с помощью project-stub [21] — проекта с заранее предустановленными технологиями и инструментами. Начинать знакомство с ним стоит с помощью быстрого старта по БЭМ [22].
Расширенный пример использования project-stub описан в документе Создаем свой проект на БЭМ [23].
БЭМ-методология — это набор правил и рекомендаций по организации работы над проектом.
В какой-то момент мы отделили методологию от ее практической реализации — платформы.
БЭМ-платформа — это частный случай реализации общих принципов БЭМ-методологии. Так как все технологии создавались с учетом требований наших проектов и развивались постепенно, БЭМ-платформа наиболее полно охватывает все возможности, которые предоставляет БЭМ-методология. Более подробно о ней можно прочитать здесь [24].
Все части БЭМ-платформы интегрированы для совместной работы, но могут быть использованы и по отдельности. Каждая часть решает конкретную задачу и её можно настраивать под свой процесс и заменять на другие.
Выбирайте наиболее подходящий способ для вашего проекта, экспериментируйте. Можно даже выкладывать свои проекты сайт [25]. Мы будем благодарны вам за обратную связь.
Автор: Яндекс
Источник [26]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/111289
Ссылки в тексте:
[1] блок: https://ru.bem.info/method/key-concepts/#Блок
[2] элементов: https://ru.bem.info/method/key-concepts/#Элемент
[3] модификатора: https://ru.bem.info/method/key-concepts/#Модификатор
[4] альтернативных схем именования: https://ru.bem.info/method/naming-convention/#Альтернативные-схемы-именования
[5] инструментов БЭМ: #tools
[6] миксом: https://ru.bem.info/method/key-concepts/#Микс
[7] форуме: https://ru.bem.info/forum/656/
[8] уровни переопределения: https://ru.bem.info/method/key-concepts/#Уровень-переопределения
[9] i-bem: https://ru.bem.info/technology/i-bem/
[10] Jade: http://jade-lang.com/
[11] BEMJSON: https://ru.bem.info/technology/bemjson/
[12] BEMHTML: https://ru.bem.info/technology/bemhtml/current/rationale/
[13] сборка: https://ru.bem.info/method/build/
[14] bem-tools: https://ru.bem.info/tools/bem/bem-tools
[15] ENB: https://ru.bem.info/tools/bem/enb-bem/
[16] DEPS: https://ru.bem.info/technology/deps/
[17] bem-core: https://ru.bem.info/libs/bem-core/
[18] bem-components: https://ru.bem.info/libs/bem-components/
[19] Dist: https://ru.bem.info/libs/bem-components/v2.4.0/#Подключение-предсобранных-файлов-библиотеки-dist
[20] описании библиотеки: https://ru.bem.info/libs/bem-components/current/#Использование
[21] project-stub: https://ru.bem.info/tutorials/project-stub/
[22] быстрого старта по БЭМ: https://ru.bem.info/tutorials/quick-start-static/
[23] Создаем свой проект на БЭМ: https://ru.bem.info/tutorials/start-with-project-stub/
[24] здесь: https://ru.bem.info/method
[25] сайт: https://ru.bem.info/built-with-b/
[26] Источник: https://habrahabr.ru/post/276035/
Нажмите здесь для печати.