Базовые понятия и принципы БЭМ

Сухой остаток моего доклада, вольная трактовка теоретической части БЭМ-методологии. Если вы ничего не знаете про БЭМ, то лучше начать с bem.info.

БЭМ — блок, элемент, модификатор.

Блок. С блоком всё очень просто. Блок это блок. Блоком может быть всё что угодно, любая сущность. Быть или не быть сущности блоком зависит от точки зрения того, кто выделяет сущности. Блок может быть простым или составным. Простой блок состоит из одной и единственной детали, составной — из нескольких. У блока есть имя.

Детали составляющие блок называются элементами. Элементы в блоке могут быть уникальными, могут повторяться, могут быть обязательными или опциональными. Элемент не существует без блока и имеет смысл только в рамках него. Описывается элемент собственным именем и именем блока которому он принадлежит. По существующему канону элемент является непосредственной частью именно блока, но не других элементов. Это постулированное правило, объясняемое исключительно из опыта и предположения, что для описания интерфейсов и следования АНБ-принципу достаточно двухуровневой структуры.

Блок и элемент определяют сущность и её состав. Свойства сущностей задаются с помощью модификаторов.

Модификатор — описание блока или элемента. Модификатор не может влиять на состав и структуру сущностей, не может порождать элементы блока, модификатор задаёт свойства, специфику и отношения между сущностями. Модификаторы описывают любые свойства: поведение, внешний вид, содержимое, отличительные черты — всё, что угодно. Одна сущность (блок/элемент) может описываться множеством модификаторов. Много свойств — много модификаторов. Модификатор описывается собственным именем и значением, а также именем блока или элемента к которому он применяется. Очень важно то, что модификация не существует сама по себе, она всегда имеет точку приложения в виде блока или элемента. По сути, модификация это предикат — всегда описывает связь между субъектом (блоком или элементом) и какой-то другой сущностью, которая чаще всего не представлена в БЭМ-пространстве собственным блоком или элементом.

Имя БЭМ-сущности и её описание в наборе технологий составляют декларацию сущности.

Структурная композиция БЭМ-сущностей называется БЭМ-деревом. БЭМ-дерево в конечном счете отражается в DOM-дерево. Следует понимать, что БЭМ-дерево это частный случай использования задекларированных блоков, всего лишь набор экземпляров БЭМ-сущностей. Когда на БЭМ-дереве мы видим вложенность блоков, это не означает, что один блок является частью другого. Сочетаются экземпляры блоков, но не сами блоки. На уровне деклараций блоки ничего друг о друге не знают (по умолчанию).

Целостность композиции блоков поддерживается в рамках тех подходов к связыванию, которые предполагает БЭМ.

Основа связывания и сочетаемости блоков — концепция абсолютно независимых блоков. Идея АНБ состоит в том, что нужно таким образом выделять сущности-блоки, чтобы их можно было беспрепятственно переиспользовать в любом другом месте. Блоки не должны иметь зависимостей и оказывать влияния на другие блоки. Например, старание избежать в CSS каскадных селекторов — это способ избежать неконтролируемых связей, возникающих в следствие вложенности узлов.

Носителем БЭМ-терминов в коде являются CSS-классы. БЭМ-нотация классов содержит в себе часть связей, реализуя тем самым АНБ-принцип. БЭМ-классы не только следствие того, что нужно обеспечить независимость блоков. Разработка в БЭМ-терминах означает, что классы появляются раньше всего остального, а то что не имеет класса, не определено (невидимо) на БЭМ-уровне.

Говоря об АНБ нельзя не упомянуть конструктор Lego. Lego — самая заезженная, но самая точная метафора, иллюстрирующая принцип. Блок это кирпичик Lego — маленький, независимый компонент. Суть АНБ-подхода в том, чтобы описать набор таких кирпичиков, а потом собирать из них всё что угодно. Сочетаемость блоков возникает как следствие формы блоков — их интерфейса.

Тем не менее, не всякую конструкцию возможно и целесообразно получать таким способом. Для получения нужных свойств и поведения иногда необходимо зафиксировать в коде требуемые зависимости и связи. Связь, как таковая, противоречит идее абсолютно-независимых блоков, однако следует понимать, что АНБ это идеальная концепция, на неё надо ориентироваться и максимально ей соответствовать, но в реальности, в чистом виде, она встречается не так часто.

Какие БЭМ-сущности теоретически можно связывать?

Блок со своими элементами связывать явно — не имеет смысла, поскольку связь заложена на уровне синтаксиса. Элемент всегда «знает» какому блоку он принадлежит.

Связь элементов блока с модификатором блока — наиболее частый и довольно приемлемый вариант. Область действия такой связи ограничена пределами блока (модификатора блока). Появляется опасность, что при рекурсивной вложенности блоков, между ними возникнут конфликты связей с внутренними элементами, но эта цена, которую приходится платить за простой доступ к элементам блока с помощью модификатора.

Связь элементов блока между собой (по умолчанию элементы блока ничего про друг друга не знают). Связь аналогична предыдущей, но встречается гораздо реже, поэтому условно можно считать её безопасной.

Связи между блоками и/или элементами, принадлежащих разным блокам — в отличие от предыдущих вариантов, действуют во всем пространстве блоков. Это делает код более запутанным, увеличивает его связность и повышает вероятность конфликтов, следует всячески избегать таких связей.

Расширить сочетаемость по АНБ можно за счет миксов.

Микс — это совмещение разных БЭМ-сущностей на одних узлах DOM-дерева. Можно строить сложные композиции из простых блоков за счет «подмешивания» одних блоков к другим. Тем самым достигается минимизация и повторное использование кода (во всех технологиях). При миксовании предполагается достижение положительного комбинаторного эффекта, но наряду с очевидными плюсами, могут возникать неприятные побочные эффекты в виде наложения технологических деклараций. Если несколько сущностей пересекаются по отдельным моментам деклараций, то какая из них будет иметь приоритет на узле, не зная предыстории, предсказать невозможно (блоки по умолчанию равны).

Отдельной темой является возможность использовать микс как способ связи абсолютно-независимых блоков. В этом случае можно сказать, что миксы «узаконивают каскад». Микс сам по себе не задекларирован как отдельная сущность, поэтому разница между простой связью и миксом неочевидна (потому что её нет в таком случае).

Миксование поощряет появление «лишних» межблочных связей. При составлении композиции из блоков и использовании элементов одного блока как части другого, есть соблазн обеспечить встраиваемость между ними за счет связей. Поскольку не приходиться дублировать код, то можно очень быстро получить требуемый результат. Однако это порочная практика, поскольку такой код противоречит АНБ-принципам. Если миксуются развесистые и/или часто встречающиеся блоки, то это гарантированный выстрел себе в ногу. Вывод — в межблочных связях следует быть очень разборчивым.

Можно избежать связей между независимыми блоками если усложнить «форму» блоков при помощи модификаторов.

Также, следует отличать микс от «глобальных модификаторов». Глобальный модификатор — это блок, который нужен только для того, чтобы примешиваться к другим блокам, придавая им какие-либо свойства. В этом случае происходит подмена модификации (про свойства) блоком (про сущность) Отсутствие глобальных модификаторов это одно из принципиальных отличий БЭМ от других фреймворков. Это не означает, что не может быть блоков-хэлперов, но они должны иметь самостоятельную ценность. Подмешиваемый блок не должен быть замаскированной модификацией и нести только свойства, у него должна быть своя семантика, пусть из предметной области отличной от той, в которой находится основная сущность.

Вопрос выделения и именования БЭМ-сущностей составляет самую нетривиальную часть процесса разработки.

Самая главная рекомендация — «Не умножать сущностей без необходимости», т.е. не плодить блоки. Если какой-либо существующий блок описывает новый объект достаточно полно, то скорее всего нужен модификатор, а не новый блок. Модификатор имеет контекст в виде блока и это сокращает его область видимости/наблюдаемости как БЭМ-сущности. С другой стороны, существенные с точки зрения предметной области объекты лучше описывать как отдельные блоки. Если необходимо повысить надежность конструкции, или увеличить быстродействие, то можно также заменить модификатор блока отдельным блоком. Обратная сторона такого подхода — увеличение количества сущностей.

Все сущности формируют библиотеку блоков. Чем больше сущностей, тем сложнее держать их в порядке и находить нужную. Блоки могут быть разными по размеру и «фактуре» но на практике мы имеем дело только с их именами, а они «на ощупь» между собой ничем не отличаются. Не плоди сущности!

Все блоки равны между собой. Чтобы управлять множеством равнозначных блоков вводится понятие уровня переопределения. Уровень — это коллекция деклараций БЭМ-сущностей. Будучи приоритезированными, уровни позволяют организовать систему, при которой сущности с высоких уровней могут дополнять или переопределять сущности, объявленные на нижних уровнях.

БЭМ задаёт правила грамматики, но не говорит о том как писать на её основе осмысленные предложения. Даже используя однозначные названия сущностей невозможно обеспечить семантически верную конструкцию БЭМ-сущностей. Префиксы и правильная нотация не делают код написанным по БЭМ если сущности не выделены правильно.

БЭМ ничего не говорит про каскад, БЭМ — про связи. Каскад в силу своей природы часто становится воплощением плохих связей, это очень мощный инструмент и надо уметь его использовать правильно.

То, как выделять и структурировать блоки всегда остаётся за разработчиком. Синтаксис БЭМ содержит правильные паттерны и подталкивает разработчика к их использованию при реализации связей. БЭМ прежде всего язык объектно-ориентированного проектирования. Предметная область, описанная в БЭМ-терминах, это дополнительный слой абстракции, который лежит между обыденным языком и кодом в определенной технологии. Описать в БЭМ-терминах можно всё. Имеет ли это смысл? — открытый вопрос.