company_banner

Масштабирование наоборот: БЭМ-методология Яндекса на небольших проектах

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

    Скорее всего, вы уже знаете об одной из таких методологий, разработанной Яндексом, — БЭМ. БЭМ утверждает, что трёх сущностей (блоков, элементов и модификаторов) достаточно для написания HTML и CSS, задания структуры кода и компонентной структуры с последующим масштабированием проекта до самого высокого уровня.

    Я проработал в Яндексе достаточно долго и видел, как эта методология работает на больших проектах. В Яндексе БЭМ используют для разработки CSS- и JavaScript-компонент, с помощью этой методологии также пишут шаблоны и задают зависимости между компонентами. Есть БЭМ-инструменты, поощряются различные эксперименты с кодом, исследования. В масштабах большой компании эти трудозатраты окупаются и дают Яндексу возможность быстро и качественно разрабатывать сотни сервисов одновременно.

    Могут ли маленькие команды получить от БЭМ то же самое? Я совершенно не был в этом уверен. Всё же БЭМ — абстракция, которая поставляется вместе с инструментами и технологиями. Для маленькой компании польза от переключения на «полный стек» этих технологий — сомнительна, многие из инструментов изначально приспособлены под крупные и сложные задачи. Быть может, тогда полезной окажется сама идея, сама методология?

    Изначально эта моя статья была опубликована в известном многим журнале Smashing Magazine. Но я решил, что и на Хабре она может быть интересна, ведь многие здесь занимаются собственными небольшими проектами.



    К вопросу о том, может ли БЭМ применяться в таковых, я вернулся чуть более года назад, когда переехал в Берлин для работы в небольшой стартап-компании Deltamethod. Планы на разработку у компании были смелые, и мы с командой решили попробовать БЭМ-подход. Хотелось получить те же бонусы, что были у Яндекса: переиспользование кода, «живой» Style Guide, масштабируемость и быструю разработку. В дополнение к этому мы хотели в целом сохранить используемый стек технологий и улучшать код постепенно, а не переписывать весь сервис с нуля.

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

    Основы БЭМ


    Давайте вспомним основы. Утверждается, что семантика — это фундамент веб-разработки, но различные фронтенд-технологии используют разные семантические модели. Современное веб-приложение на уровне HTML чаще всего просто нагромождение тегов div и span. CSS как технология вообще не предлагает какой-либо структуры. Высокоуровневые JavaScript-компоненты используют те или иные абстракции, но они слабо связаны с CSS или HTML-разметкой. С точки зрения дизайнеров и UX-специалистов, интерфейсы вообще описываются терминами, далекими от технической реализации. Тем не менее все эти предметные области мы используем вместе. Самое время вспомнить про БЭМ: ведь это общая семантическая модель для разметки, стилей, кода и UX. Посмотрим поближе.

    Блоки


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

    Например, блоками могут быть:
    • заголовок,
    • кнопка,
    • навигационное меню.

    Чтобы задать блок, нужно придумать ему имя и определить его назначение. В интерфейсе может одновременно присутствовать несколько экземпляров одного и того же блока (например, разные кнопки или несколько меню). Любой веб-интерфейс можно описать как иерархическую структуру блоков. Простейший пример — само HTML-описание страницы, если представить, что каждый тег — это блок. Правда, с точки зрения семантики это малоосмысленно, потому что HTML был разработан для представления и оформления текстов, а не интерактивных веб-приложений.

    Элементы


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

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

    У элементов тоже есть названия. Если внутри блока несколько одинаковых элементов, то они идут под одним именем (например, ячейки таблицы или пункты списка). Элементы определяются по смыслу, а не исходя из HTML-вёрстки блока; так, отдельный элемент может быть представлен сложной HTML-структурой.

    Модификаторы


    Модификаторы — флаги у блоков или элементов, они определяют свойства или состояния. Модификаторы бывают булевыми (например, visible: true или false) или или представляют собой пару «ключ — значение» (code>size: large, medium, small). Это чем-то похоже на атрибуты в HTML, но всё-таки не то же самое. У сущности может быть несколько модификаторов, если эти модификаторы описывают разные вещи.

    Блоки в DOM


    Как использовать БЭМ, если мы всё ещё вынуждены писать HTML? Нужно соглашение об именовании, которое свяжет DOM-узлы с БЭМ-сущностями. Для задания этой связи БЭМ использует CSS-классы. При этом блоки, элементы и модификаторы не размещаются на DOM-узлах эксклюзивно; на одном теге может быть определено сразу несколько блоков, либо же элемент блока может быть объединен с контейнером другого блока. Использование одного и того же DOM-узла для размещения нескольких сущностей называется «микс». Помните, что миксы сделаны для удобства, совмещать можно только совместимое: не превращайте всё в кашу, смешивая блоки и элементы.

    Дерево БЭМ (BEM tree)


    Формируя документ из БЭМ-сущностей, начиная с корневого блока (<body> или даже <html>) и заканчивая глубоко вложенными блоками, вы создаёте семантический слой поверх существующей DOM-структуры. Этот слой называется БЭМ-деревом (BEM tree). БЭМ-дерево даёт возможность взаимодействовать с целым документом в терминах БЭМ, с точки зрения семантики, абстрагируясь от особенностей DOM-реализации.

    Первые шаги


    Если вы уже задумываетесь, не попробовать ли БЭМ на проекте, возникает закономерный вопрос: «Как перевести на БЭМ существующий проект, можно ли это сделать постепенно?»

    Конечно, можно. Давайте начнем с того, что выделим несколько блоков. Мы начнём с семантики, а конкретные технологии, такие как CSS и JavaScript, обсудим позже. Как вы помните, блоком может быть только самостоятельная сущность. Например, заголовки — это блоки. У них нет внутренних элементов, но уровни заголовков (от самого большого до самого маленького) могут быть определены как модификаторы вида «ключ — значение».

    Если позже понадобятся ещё уровни, мы определим дополнительные модификаторы. Тут я скажу, что разработчики HTML4, скорее всего, были неправы, изобретая <h1> ...<h6>. Они создали разные теги, в то время как требовались модификаторы одного и того же блока-сущности. В HTML5 это пытаются исправить с помощью секционных элементов, но с поддержкой в браузерах пока дело обстоит не очень хорошо.

    Скажем, мы получили такое:
    BLOCK heading
    MOD level: alpha, beta, gamma
    

    В качестве второго примера можно взять форму, её элементы управления (или контролы, как их называют) — это тоже блоки: и поля ввода, и кнопки, и прочие кирпичики. В HTML это всё реализовано довольно беспорядочно. Разные по смыслу вещи (поля ввода, радиокнопки и флажки-чекбоксы) объединены в один тег , a другие (очень похожие на них) определены отдельными тегами и . Некоторые сущности, такие как метки или автоматические подсказки datalist, вообще не имеют смысла без привязки к конкретным контролам и подходят на роль элементов внутри блоков, составляющих форму.

    Посмотрим, можно ли это исправить:
    BLOCK text-input
    MOD multiline
    MOD disabled
      ELEMENT text-field
      ELEMENT label
    

    Поле ввода нужно для того, чтобы туда можно было написать текст. Если текст многострочный, семантически ничего не меняется, поэтому multiline — это только модификатор. В HTML у этих двух случаев разметка по техническим причинам будет разной, но это нормально — сейчас мы сосредоточены на определении семантики, а не конкретной реализации. Ещё у блока есть элементы textfield и label. Позже может понадобиться добавить и другие элементы, такие как иконка статуса, место для сообщения об ошибке или автоподсказка.
    BLOCK checkbox
      ELEMENT tick-box
      ELEMENT label
    

    BLOCK radio
      ELEMENT radio-button
      ELEMENT label
    

    Эти два блока довольно очевидны. По-прежнему есть элемент <label> и элемент, представленный тегом <input>.

    BLOCK select
    MOD disabled
    MOD multiple
      ELEMENT optgroup
      ELEMENT option
        MOD disabled
    	MOD selected
    

    В случае select метки label нам не нужны, а все остальное более-менее похоже на обычный контрол select. Технически можно переиспользовать существующий тег и его структуру. Обратите внимание, что и у блока select, и у его элемента option может быть модификатор disabled. Важно, что это разные модификаторы: первый выключает весь контрол целиком, а второй — только конкретный option (кстати, отличный пример модификатора на элементе!). Попробуйте и в своём проекте найти подобные примеры блоков.

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

    Пусть ваш CSS говорит сам за себя


    Наверняка вы слышали, что БЭМ оказывает большую помощь в организации и написании CSS. А как именно и почему?

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

    Система именования БЭМ для CSS


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


    Контейнеры блоков получают CSS-класс, состоящий из префикса и имени блока:
    .b-heading
    .b-text-input
    

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

    Контейнеры элементов внутри блока получают CSS-класс из имени блока, двух подчёркиваний и имени элемента:
    .b-text-input__label
    .b-text-input__text-field
    

    Элементы элементов не используются (например, имя класса .b-block__elem1__elem2 не соответствует БЭМ-подходу).

    Модификаторы относятся или к блоку, или к элементу конкретного блока. Их CSS-класс формируется из класса их «владельца», далее следует подчёркивание, и имя модификатора:
    .b-text-input_disabled
    .b-select__option_selected
    

    Для булевых модификаторов этого достаточно. Если модификатор — пара «ключ-значение», добавляем ещё одно подчёркивание для отделения значения модификатора:
    .b-heading_level_alpha
    

    Классы-модификаторы используются совместно с классом блока или элемента:
    <div class="b-heading b-heading_level_alpha">BEM</div>
    

    Чем привлекателен CSS по БЭМ-методологии


    Достаточно одного класса


    Нередко CSS сильно зависит от структуры документа. Меняется структура — ломается CSS. С BEM мы перестаём использовать имена тегов и ID, а опираемся только на имена классов. Это позволяет нам минимально зависеть от структуры документа.

    Специфичность CSS-правил: проблема и решение


    Большие объёмы CSS сложно поддерживать в том числе из-за того, что они могут взаимно влиять друг на друга, порой непредсказуемо доопределяя или переопределяя уже имеющиеся правила.

    У этой «проблемы» есть имя: специфичность CSS-правил. Исходно, наличие как имён тегов, так и идентификаторов меняет специфичность правил таким образом, что при наследовании свойств (которое используется в CSS очень часто) переопределение правил возможно только с селекторами той же самой или более высокой специфичности. Проекты, сделанные на БЭМ, практически не страдают от этой проблемы.

    Рассмотрим пример. Пусть у вас есть таблица с такими вот стилями:

    td.data { background-color: white }
    td.summary  { background-color: yellow }
    

    Однако в другом компоненте вам потребовалось переопределить цвет фона отдельной ячейки:
    .final-summary { background-color: green }
    

    Это не сработает, потому что tag.class всегда будет иметь более высокую специфичность по сравнению с .class, независимо от их взаимного положения в CSS-коде.

    Чтобы всё заработало, вам придётся добавить имя тега:

    td.final-summary { background-color: green }
    

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

    Прощай, каскад?!


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

    Как это возможно и почему это важно? Разве неверно, что каскад должен использоваться в CSS, иначе зачем они называются Cascading Style Sheets?

    Вернёмся к правилам именования и вспомним, что каждый БЭМ-класс имеет уникальное имя и является самодостаточным. За редкими исключениями он не зависит ни от имён тегов, ни от идентификаторов, и разные блоки никогда не пересекаются по именам классов. Это означает, что вам, скорее всего, достаточно указать один (и только один!) класс, чтобы:
    • описать стили самого блока;
    • описать стили любого элемента внутри блока;
    • добавить дополнительные стили или переопределения с помощью модификатора.


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

    На маленьких и средних страницах CSS редко является главной проблемой замедления быстродействия, но набор CSS-правил должен применяться заново при каждом изменении документа. Когда ваш проект растёт, скорость работы CSS рано или поздно станет важным фактором. Специалисты по юзабилити любят повторять, что 250 миллисекунд — это порог, в случае превышения которого действие не воспринимается как мгновенное. Чем быстрее ваш CSS изначально, тем больше пространства для манёвра будет у вас, чтобы поддерживать ощущение «всё летает».

    Получается, БЭМ отменяет каскад в CSS?! Если всерьёз, то, конечно же, нет. Есть случаи, когда каскад нужен, — если требуется указать два или более классов в одном селекторе. Например, если модификатор блока влияет на стили отдельных его элементов:
    .b-text-input_disabled .b-text-input__label
    {
       display: none;
    }
    

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

    Есть и другие примеры, когда каскад необходим (внутренние нетривиальные зависимости элементов, сочетания модификаторов, CSS-хаки). Живые проекты всегда богаче и сложнее, чем любая методология (даже БЭМ!), но подобные стили вряд ли потребуются вам часто.

    Абсолютно Независимые Блоки (коцепция АНБ)


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

    Альтернативные соглашения именования классов на основе БЭМ


    Описанная в статье система именования классов по БЭМ — не единственная. Возможно, вы слышали о других вариантах. Что лучше выбрать?

    К примеру, Николас Галлахер (Nicolas Gallagher) предложил некоторые улучшения, и этот пример не единственный. Многие предлагали для обозначения модификаторов использовать атрибуты вместо классов, синтаксис разделителей может быть разным, префиксы имён можно не использовать вообще или вводить много разных префиксов для разных целей.

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

    Разумеется, сама БЭМ-методология на порядок важнее того, сколько чёрточек мы напишем в имени класса. Если вам нравится другой способ именования — используйте его, только убедитесь, что у вас есть на то технологическая причина.

    Семантический JavaScript и БЭМ-ориентированный код


    Как применить БЭМ-модель к JavaScript-коду?
    Многие авторы и разработчики видят в БЭМ только соглашение по именованию классов в CSS, но это заведомо упрощённый подход.

    Методология БЭМ была разработана, чтобы на всех уровнях (HTML, CSS, JavaScript, шаблоны, дизайн интерфейсов) можно было вводить единую семантику — своего рода polyfill, устроенный по такому же принципу, как jQuery, и предоставляющий единое гибкое API поверх пёстрого набора методов для работы с DOM.

    HTML был изначально разработан как язык разметки текста, но сейчас мы используем его для построения интерактивных интерфейсов. Экспериментальные стандарты, такие как Web Components, пытаются вернуть нам контроль над семантикой, но БЭМ можно использовать уже сейчас во всех браузерах, сохраняя потенциал для интеграции с новыми современными технологиями, так как сама идея не зависит ни от конкретного API, ни от конкретной технологии.

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

    Учимся декларировать


    Первый шаг — принять декларативную парадигму. Декларативное программирование — подход, который делает упор на «что», а не на «как». Регулярные выражения, SQL и XSLT — хорошие примеры декларативных технологий, так как они определяют не последовательность выполнения низкоуровневых операций, а логику, стоящую за ними. Декларативное программирование есть описание набора условий, каждому из которых соответствуют определённые действия.

    В БЭМ условия могут быть выражены через модификаторы, а действия могут совершаться только над блоками и элементами. Примеры кода в этой статье вдохновлены фреймворком i-bem.js, который создал и опубликовал под свободной лицензией Яндекс, но я уверен, что любой продвинутый фреймворк позволяет реализовать схожие идеи, в том числе потому, что декларативный подход вообще очень близок веб-технологиям.

    BEMDOM.decl('b-dropdown', {
       onSetMod: {
          disabled: function(modName, modVal) {
             this.getLabel().setMod('hidden', 'yes');
             if (modVal === 'yes') {
                this.getPopup().hide();
             }
          },
    
          open: {
             yes: function() {
                this.populateList();
             }
          }
       },
       /* … */
    

    Этот пример кода определяет действия по факту установки двух модификаторов на блоке b-dropdown.

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

    Другой пример с модификаторами на блоке b-editor:
    BEMDOM.decl('b-editor', {
       onSetMod: {
          hotkeys: {
             windows: function() {
                this.delMod('theme');
                this.loadKeyMap('windows');
             },
             emacs: function() {
                this.setMod('theme', 'unix');
                this.loadKeyMap('emacs');
                enableEasterEgg();
             },
             '': function() {
                this.clearKeyMaps();
                this.delMod('theme');			
             }
          }
       }
       /* … */
    

    Этот пример помогает понять, как модификаторами можно описать модификаторами логику перехода между состояниями.

    Методы


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

    BEMDOM.decl({ block : 'b-popup', modName : 'type', modVal : 'inplace' }, {
       appear: function() {
          // makeYouHappy();
       }
    });
    

    Этот метод определён только у блоков, имеющих модификатор type: inplace.

    Как и в «классическом» ООП-подходе, можно расширять семантически определённые методы, указывая ещё более специфичные декларации, уточняющие ранее заданное. Возможны как переопределения, так и доопределения. Пример:

    BEMDOM.decl({ block: 'b-link', 'modName': 'pseudo', 'modVal': 'yes' }, {
       _onClick : function() {
          // выполняет базовый _onClick, определённый
          // для всех экземпляров блока b-link
          this.__base.apply(this, arguments);
    
          // изменить внешний вид средствами CSS,
    	  // семантически описывая смену статуса и
          // оставляя конкретную реализацию автору таблицы стилей 
          this.setMod('status', 'clicked');
       }
    });
    

    В этом доопределении метод _onClick расширяется только для экземпляров блока b-link, имеющих модификатор _pseudo_yes. В остальных случаях используется реализация метода по умолчанию.

    Семантика постепенно переходит из HTML-разметки в JavaScript код, при этом мы используем всё те же БЭМ-сущности.

    Развесистое БЭМ-дерево


    В чём смысл декларативного подхода, если вернуться от теории к практике? Главная идея — начать работать с БЭМ-деревом, которое построено и управляется вами, а не с деревом DOM, которое отражает лишь разметку (вещь, в сущности, глубоко техническую):

    BEMDOM.decl('b-checkbox-example', {
       onSetMod: {
          js: {
             inited: function() {
                var checkbox = this.findBlockInside({
                   block: 'b-form-checkbox',
                   modName: 'type',
                   modVal: 'my-checkbox'
                });
                BEMDOM.append(this.domElem, 'Checkbox value: ' + checkbox.val());
             }
          }
       }
    }
    );
    

    Конечно же, есть богатый набор других API-методов, например this.elem('name') и this.findBlockOutside('b-block'). Я не хочу копировать документацию (она доступна онлайн), а всего лишь показываю, как вокруг БЭМ-дерева строятся методы работы с веб-приложением.

    Модификация модификаторов и контроль за контролами


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

    Установка модификаторов есть установка CSS-классов, но мы не можем эффективно отслеживать эти действия (по технологическим причинам). Поэтому, вместо прямой установки классов в CSS, i-bem.js предлагает простое API (его легко воспроизвести и в других фреймворках):

    // setter
    this.setMod(modName, modVal);
    // getter
    this.getMod(modName);
    // проверка наличия
    this.hasMod(modName, modVal);
    // переключение
    this.toggleMod(modName, modVal);
    // удаление
    this.delMod(modName);
    

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

    БЭМ-ориентированный код


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

    Вот короткий «чеклист» того, что должен уметь фреймворк:

    • Поддерживать в том или ином виде декларативный подход
    • Позволять работать с БЭМ-деревом, абстрагируясь от DOM-дерева
      Независимо от встроенного API, важна возможность в нужный момент уйти от прямого взаимодействия с DOM,
      по возможности ориентируясь на БЭМ-сущности.
    • Позволять использовать модификаторы для описания состояний
      Разумеется, может потребоваться разработка дополнительных методов или плагинов.
      Также очевидно, что не надо описывать модификаторами все состояния до последнего.
      Начните с тех, которые удобно выражать в CSS (связанные с показом или скрытием элементов, изменением внешнего вида
      в зависимости от состояний и т.п.). Не работайте с inline CSS из кода напрямую.


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

    Если вы используете jQuery, можно попробовать один из этих несложных проектов для
    БЭМ-ориентированной разработки:


    От правил именования классов — к Style Guide


    Если вы много работаете с дизайнерами, БЭМ-методология также будет полезна.

    Представьте, что у вас есть руководство по стилям проекта, сделанное Настоящим Профессиональным Дизайнером™. Скорее всего, вам его отдадут в виде увесистого PDF-файла, из которого вы узнаете об используемых в проекте шрифтах, цветовых схемах, принципах взаимодействия элементов интерфейса и прочих умных терминах. Такой стайлгайд может быть интересно прочесть, особенно в свободное от работы время, но для обычных фронтенд-разработчиков пользы от такого руководства мало: на уровне кода они оперируют совсем-совсем иными понятиями и терминами, и никакой особой связи между ними и глянцевым «стайлгайдом» не ощущают.

    Может, было бы лучше, если вы как разработчик могли говорить с дизайнером «на одном языке»? Не всем программистам интересно слушать «про фотошоп», не все дизайнеры хотят программировать. А что, если стайлгайд мог бы быть библиотекой интерфейсных блоков, описанных в терминах БЭМ? Такая библиотека включала бы в себя все основные «кирпичики», из которых и строится интерфейс сайта или приложения.

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

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

    Главное достижение, конечно, в исчезновении пропасти между кодом и дизайном, в использовании одних и тех же сущностей при проектировании интерфейсов и написании кода — притом, что дизайнерам не надо учить программирование, а разработчикам — осваивать UX-инструментарий. Дизайнер может вообще не понимать, как работает ваш код, но говорить вы уже будете «на одном языке».

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

    БЭМ как высокоуровневая документация проекта


    Давайте признаемся честно: разработчики редко пишут документацию в достаточном объёме. Передача проектов между командами, смена разработчиков — процесс нетривиальный. В поддержке кода важно минимизировать время, которое разработчик тратит на то, чтоб понять, как всё устроено, где что лежит и как вообще это работает — порой именно на это уходит львиная доля времени, а вовсе не на реализацию функциональности или исправление ошибки.

    Конечно, очень круто иметь документацию для всего, но в реальном мире её частенько не бывает. Но даже когда документация есть, она описывает методы, свойства или API модулей, но редко касается «цикла работы» компонента, его возможных состояний и переходов между ними. Причина проста: это высокоуровневая семантика, и если не применять никакой методологии, то сам по себе код не даёт инструментов для её описания, поэтому и документация к коду часто не помогает: все методы описаны досконально, а как что работает — непонятно.

    Однако, если проект использует принципы БЭМ-ориентированного кода, описанные выше, вы сразу же сможете понять следующее:

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


    С примерами обычно проще. Что вы можете сказать о том, как устроен и работает описанный ниже блок?
    // блок
    b-popup
      // модификаторы и их значения
      _hidden
      _size _big
            _medium
    	    _large
      _direction _left
                 _right
    	         _top
    	         _bottom
      _color-scheme _dark
                    _light
      // элементы
    	__anchor-node
    	__popup-box
    	__close-btn
    	__controls
    	__ok
    	__cancel
    

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

    Заметьте, документации вы в этом примере тоже не видели. Такое БЭМ-описание можно сгенерировать автоматически силами CSS-препроцессора, описать в YAML или ему подобных языках.

    БЭМ и файловая структура


    Когда проект быстро растёт, неконсистентная файловая структура может вас сильно задерживать. Чем сложнее проект, тем более сложной и менее гибкой будет его структура. Инструменты и фреймворки не всегда хорошо помогают организовать файлы в проекте, т.к. часть из них навязывает свою, специфичную строго для данного инструмента структуру файлов и папок (а если потом переходить на что-то новое?!), а некоторые фреймворки вообще ничего на эту тему не предлагают — делай как знаешь, мол.

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

    Библиотека блоков


    Папка с блоками — «базовое понятие» любой файловой структуры, ориентированной на БЭМ-подход. Имена блоков коротки, описательны и уникальны в пределах проекта — и прекрасно подходят для именования вложенных папок. Сами по себе блоки внутри проекта равноправны, поэтому их проще хранить в виде плоской структуры как набор папок на одном уровне:

    /blocks
      /b-button
      /b-heading
      /b-flyout
      /b-menu
      /b-text-field
    

    Внешние инструменты (фреймворки и т.п.) также могут быть определены как блоки.
    Пример:

    /blocks
      …
      /b-jquery
      /b-model
    

    Внутри каждой папки блока проще всего выделить каждой «технологии» по отдельному файлу:

    /b-menu
      b-menu.js
      b-menu.css
      b-menu.tpl
    

    Более «продвинутый» подход — вынести данные для некоторых элементов и модификаторов в отдельные подпапки, реализуя модульный подход:
    /b-menu
      /__item
    	b-menu__item.css
    	b-menu__item.tpl
      /_horizontal
        b-menu_horizontal.css
      /_theme
        /_dark
    	  b-menu_theme_dark.css
    	/_light
    	  b-menu_theme_light.css
    
      b-menu.css
      b-menu.js
      b-menu.tpl
    

    Это даёт вам больше контроля над кодом, но такая структура требует времени на создание и поддержку. Выбирайте сами.

    Уровни переопределения


    Что если вам требуется расширить стили или функциональность компонент, или задействовать код в нескольких проектах одновременно? Общая (разделяемая) библитека блоков должна поддерживать переопределение и расширение функциональности. В случае JS-кода нам помогут принципы ООП, но как быть со стилями и шаблонами? БЭМ решает эту проблему, ввода для всех используемых технологий (JS, HTML, CSS) понятие уровней переопределения.

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

    Например, можно иметь библиотеку общих блоков и несколько более специфичных библиотек для отдельных страниц или разделов сайта:
    /common
      /blocks
        /b-heading
    	/b-menu
    	…
    
    /pages
      /intro
        /blocks
    	  /b-heading
    	    b-heading_decorated.css
    	  /b-demo
    	  /b-wizard
    	  …
    

    При таком подходе в /common/blocks мы будем складывать блоки, используемые во всём приложении.

    Для каждой страницы (в нашем примере /pages/intro) мы вводим новый уровень переопределения: отдельную библиотеку, /pages/intro/blocks, которая добавляет новые блоки и расширяет (если требуется) некоторые «общие» (в нашем примере обратите внимание на дополнительный модификатор _decorated для общего блока b-heading).

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

    Разделение библиотек может быть основано на форм-факторе устройства:

    /common.blocks
    /desktop.blocks
    /mobile.blocks
    

    Библиотека common находится на верхнем уровне, а mobile или desktop расширяют её, являясь следущими уровнями переопределения. Этот же механизм позволяет нескольким проектам использовать общие блоки, в том числе и общий набор интерфейсных компонент, реализующий единый стиль на нескольких сайтах или сервисах.

    Сборка


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

    Яндекс выпустил инструмент-сборщик с открытыми исходниками по имени Борщик, который поможет собрать вместе файлы JavaScript и CSS и облегчит подключение внешних инструментов для их дальнейшей оптимизации, например UglifyJS или CSS Optimizer. Есть решения типа RequireJS, которые также помогают реализовать сборку, описание и отслеживание зависимостей.

    Хочется ещё больше возможностей и больше фокуса на БЭМ-методологию? Попробуйте bem-tools.

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

    Утилиты, библиотеки, фреймворки... что дальше?


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

    БЭМ научил меня мыслить вне рамок конкретных фреймворков и утилит.

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

    Хотите узнать больше? Заходите на сайт БЭМ, читайте статьи, знакомьтесь с кодом, загружайте полезные модули, задавайте вопросы и помогайте развивать проект.
    Метки:
    Яндекс 664,97
    Как мы делаем Яндекс
    Поделиться публикацией
    Комментарии 54
    • 0
      никак не мог найти ответ на вопрос, а как можно прикрутить bem-tools на проект без использования BEMHTML шаблонизатора, и использовать привычный html, подтолкните хотя бы куда копать
      • +1
        А для чего вам bem tools? Если вы хотите собирать тулзами проект, то можете взять ENB он может собирать все что угодно, а тулзы можете юзать для работы с файловой системой.
        • +3
          попробуйте gulp-bem этот инструмент позволит вам собирать только CSS:

          var levels = ['base', 'blocks']
          var deps = bem.objects(levels);
          
          deps.src('{bem}.css')
              .pipe(concat('index.css'))
              .pipe(gulp.dest('./dist'));
          
          • 0
            А можно и на чистом gulp:

            gulp.src(['base/**/*.css','blocks/**/*.css'])
                .pipe(concat('index.css'))
                .pipe(gulp.dest('./dist'));
            
          • +1
            Для простой сборки БЭМ-проекта можете попробовать grunt-bemaker.
          • +2
            Спасибо автору! Отличная статья. Обязательна к прочтению всем сомневающимся.
            • +1
              пожалуйста :) задавайте вопросы, если есть :)
            • 0
              Когда читаю про БЭМ, всегда мучает вопрос: почему вы выбрали схему «A B», а не «A > B»? Ведь тогда не требовалась бы сборка проекта, да и css вполне читабелен был бы.
              • 0
                можно подробнее о том, про какую схему идёт речь?
                • 0
                  Не совсем про схему, про селектор css ">"
                  К примеру:
                  .blockX { }
                  .blockX > .item { }
                  .blockX > .item > .something { }
                  А не:
                  .blockX { }
                  .blockX__item { }
                  .blockX__something { }

                  В первом варианте сразу видно какой элемент в какой вложен, во втором между.blockX и .blockX__something может быть куча слоев, то есть css, по сути, не отображает структуру html.
                  • +8
                    Понятно. Есть несколько причин (о некоторых из них я написал в этой статье, кстати):

                    1. Миксы. Очень часто надо «смешать» несколько БЭМ-элементов на одной ноде, и если нет префиксов и имя элемента не содержит имени блока, совершенно неясно, какой элемент к какому блоку относится.
                    2. Работа с BEM из JavaScript. Удобно получать готовую ссылку на элемент по имени класса, а не делать вложенный поиск по селекторам.
                    3. Вес (специфичность) селекторов и возможности переопределения и доопределения стилей. У селектора .block > .elem1 > .elem2 иной вес, чем у .block__elem2, переопределить его можно только через селектор такого же веса.
                    4. Гибкость HTML. В БЭМ вообще не очень приветствуется, если элементы и их отображение сильно зависят от структуры. Обойтись без этого сложно, но специально фиксировать, что элемент — прямой потомок (селектор >) — неудобно, завтра ваш коллега добавит div-обёртку и все стили сломаются. В БЭМ, когда он ещё был АНБ, иногда писали селекторы вида .block-name .elem, без селектора >, но отказались (см. пункт [1]).

                    Кстати, БЭМ не должен отображать структуру HTML :) Его задача — перевести DOM-дерево в BEM-дерево, наложив сверху CSS-классы как overlay, и структура при этом возникает новая.
                    • 0
                      1. Не до конца понял, можно пример смешивания из практики?
                      2. Я в ">" другой минус увидел, если, как в четвертом пункте, добавился новый слой, то надо будет как-то контролировать его добавление в js (при условии что используется $(".blockX > .item"), а не $(".blockX .item")).
                      А так, селектор есть селектор — пишется один раз.
                      3. Тут поспорю: при использовании ">" строка в css становиться больше, но, опять таки, она отображает структуру и гораздо нагляднее показывает на каком элементе срабатывает модификатор и как.
                      4. Теоретически такой «коллега» увидит по F5, но, да, без панно всех мест не отследить.

                      >и структура при этом возникает новая
                      Ох, не нравится мне когда структура одного и того же отличается, обычно это проблемы.
                      А есть причины менять структуру?
                      • +2
                        1.

                        <div class="b-block"> <!-- ... какая-то разметка --> <div class="b-widget"> <div class="b-block__container b-widget__item"> <!-- --> </div> </div> </div>

                        Вложенный div (одна и та же нода) семантически является элементом container блока block и элементом item блока widget. Если не использовать BEM-именование, было бы <div class="container item"></div>, и неясно, кто чей (а ещё оба элемента могли называться item, тогда вообще весело)

                        2. В разметке бывает удобно переносить куски layout'а в другие места и знать, что JS не сломается. Чем меньше в JS зависимостей от структуры блока, тем лучше (это мой личный опыт, подтверждённый). Если б меня заставили перейти на схему с явно описанной структурой в стиле "A > B", я б лично повесился в тот же день, but your mileage may vary :)

                        3. Не очень понял про спор насчёт специфичности. Дело вовсе не в длине строки, а в весе правил, меняется CSS Specificity, об этом есть абзац в статье. Плюс, в BEM всегда понятно, на каком блоке или элементе срабатывает модификатор, потому что модификатор всегда привязан к блоку или элементу, «абстрактных» модификаторов нет вообще.

                        Про структуру — вообще, структура должна быть описана шаблоном, это не уровень CSS, и тем более не JS. Жизнь не идеальна, но меньше связности == меньше регрессий при правках.
                        • 0
                          Простите, всеравно не понимаю пример из 1.
                          Можете менее абстрактно объяснить, пожалуйста — почему один и тот же элемент может принадлежать разным блокам? Пример из жизни?
                          • 0
                            Вижу из обсуждения ниже: блок-кнопка становится элементом блока-радиогруппы.
                            Но тогда, можно ли так?
                            <div class="b-widget b-block__container">

                            Или миксуются только элементы, блоки с элементами смешивать нельзя?
                            • 0
                              так можно, можно смешивать что угодно с чем угодно
                              • 0
                                Но вдруг это — не канонично :)
            • +1
              Лучшая статья про BEM! Даже при всей моей любви к Яндексу, этот пост более информативен, чем «родной» экскурс по сей методологии на Хабре.
              • +1
                Спасибо :)

                Оригинальная статья (на английском) была мною начата (как и написано в предисловии) как набор рекомендаций и пояснений про BEM для ребят из группы фронтенд-разработки, которой я руковожу тут, в компании Deltamethod в Берлине. Про основы BEM мало туториалов на английском, а какие есть — сделаны людьми, которые понимают BEM только как правила CSS-нейминга (а не как методологию). Уже потом я подумал, что можно сделать из этого полноценную статью :-)
                • +1
                  Это вам спасибо.

                  А оригинал я тоже читал (но на английском не так детально все было для меня) и даже рекомендовал его к переводу в одной из своих подборок эгоист.
                  • +1
                    Вопрос про английскую версию и детальность: дело в разнице языков, или в русском переводе формулировки другие? Я переводил более-менее один-в-один, но опыт перевода самого себя с английского на русский для меня нов; плюс, я не думал и не писал по-русски, когда делался оригинал статьи для Smashing. Интересно сравнить оба варианта со стороны :)
                    • +1
                      В моем случае — разница языков. К сожалению по другому сравнить не могу. Но я уверен, что оба варианта детально раскрывать суть и смысл БЭМ =)
                  • –1
                    Макс,

                    то есть туториалы отсюда bem.info/tutorials/ не помогают?
                    • +5
                      для моего случая и для начинающих — не помогают совсем, увы :( эти туториалы — и вообще весь bem.info — о том, как начать использовать «полный стек» БЭМ, а у меня была задача понять, как его можно НЕ использовать и при этом получить плюсы от внедрения методологии как таковой. это очень важная разница, критичная.

                      плюс, по ссылке нет материала для «совсем новичков», считается, что азы можно выучить самому, но для англоязычной аудитории это неверно.

                      мои ребята в Берлине просили материала на порядок более простого — про смысл всего подхода, про примеры выделения блоков в существующем коде, про подробности naming convention и зачем она нужна.
                      • 0
                        запланировали с Володей пачку документов. наверное, приду к тебе еще с вопросами. спасибо
                  • 0
                    а родной — это какой?
                    • 0
                      А я тут немного натупил — не сразу заметил, что этот пост в корпоративном хабе присутствует, поэтому он тоже родной. Ну а так в целом, был же пост про БЭМ от Яндекса.
                      • 0
                        я могу, конечно, ошибаться, но считаю, что этот пост от нашей команды первый
                        • 0
                          Эмм. Я писала пост на Хабр, который был очень посещаем и с которого до сих пор идёт на bem.info траффик.
                          • 0
                            речь о посте в корблог. до этого поста в корблоге постов про БЭМ не было. или я не права?
                            • 0
                              Мне показалось, что «этот пост от нашей команды первый» не про корпблог, а про команду. Извините.
                              • 0
                                про корблог. не в корблог был твой пост «от команды» и много постов от сообщества, те пользователей
                  • 0
                    Элементы элементов не используются (например, имя класса .b-block__elem1__elem2 не соответствует БЭМ-подходу).

                    А почему кстати и как предлагается решать проблему, когда у блока несколько уровней вложенных элементов, которые по логике нет смысла выносить в блоки?

                    Посмотрел верстку папок на mail.yandex.ru:

                    b-folders
                        b-folders__folder
                            b-folders__folder__info
                            b-folders__folder__name
                    • +1
                      БЭМ — не канон, а методология. Я.Почта использует свой подход, у них есть элементы элементов, наверное, им зачем-то надо. В «классическом» БЭМ по умолчанию не описывается иерархия элементов, т.к. считается важным:
                      — иметь возможность свободно переставлять элементы внутри блока;
                      — оперировать только тремя сущностями (блок, элемент, модификатор) без усложнений;
                      — отделять семантически разные сущности друг от друга.

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

                      В реальной жизни идеалов не бывает. Есть у вас есть иерархия, которую надо отразить в БЭМ, можно вводить элементы элементов, можно делать b-folders__folder-name и b-folders__folder-info, можно вводить отдельный блок b-folder и у него делать элементы b-folder__info и b-folder__name.

                      Я сам работал на проектах, где был вариант БЭМ с элементами элементов, и лично для себя пришёл к выводу, что «плоская» структура блоков — гибче.
                    • +1
                      Мне всегда казалось что блок, элемент, модификатор не настолько легко воспринимаемы как группа, роль, модификатор. Мы ведь думаем о названиях — например странно смотреть на кнопку и думать как мне назвать этот блок. Ну не ассоциируется у меня кнопка с блоком. А вот с группой элементов у которых в этой группе есть какая-то роль — вполне. Про модификатор вопросов нет :)
                      • 0
                        очень хорошая идея про группу и роль, спасибо! беру на вооружение!

                        всё же блок и элемент как основные термины мне нравятся больше. во-первых, это устоявшиеся термины, это даже важнее локальных преимуществ переименования. во-вторых, группа подразумевает наличие нескольких вложенных сущностей (иначе кого мы группируем?), а в БЭМ блоки могут не иметь элементов вообще.
                        • 0
                          Кстати ещё про кнопки, допустим есть задача, сделать группу кнопок, которые ведут себя как radio-button. Обычные кнопки и группа должны выглядеть примерно одинаково и по логике такие кнопки должны быть одним и тем же блоком, а вот группа, это просто какой-то модификатор у родительского контейнера, который корректирует дочерние элементы, собственно в этом и вопрос, как это должно быть описано в идеальном или не очень BEM?
                            • 0
                              Но это же copy-paste и ещё при изменении стиля кнопок, нужно будет менять уже не один блок, а несколько, притом ещё и нужно будет ещё найти и понять, что они тоже должны быть «как кнопки». Или у вас для этого есть какое-то элегантное решение?
                              • 0
                                Вот так декларируется кнопка:
                                { block : 'button', text : 'Тема не указана' }

                                А вот так радиогруппа на основе кнопок:
                                { block : 'radio-group', mods : { type : 'button' }, name : 'Small', options : [ { val : 1, text : 'first' }, { val : 2, text : 'second' } ] }

                                Шаблоны на radio-group написаны таким образом, чтобы каждый элемент options превратился в полноценную кнопку, смиксованную с элементом radio-group.

                                Поэтому никакого копипаста нет, зато API каждого блока отвечает именно тем задачам, которые перед ним стоят.
                                • 0
                                  Ага, понял, посмотрел верстку, мы просто недопоняли друг друга, блок control-group у вас выступает как модификатор для дочерних button, а css находится в описании самой кнопки. Это нормально?
                                  • +1
                                    control-group отвечает только за визуальное объединение других контролов (например, убирает скругление углов у двух стоящих рядом кнопок или у инпута и кнопки).

                                    Поэтому реализация того, как именно меняется внешний вид конкретного блока с конкретной темой логично хранить внутри реализации его темы, а микс с control-group выступает удобным консистентным API для этой задачи.
                                • +1
                                  В мире, где не используется полный BEM-стек (про который и написана статья), эти проблемы правильнее решать либо миксинами на уровне CSS-препроцессора, обобщая в них всё визуальное, либо выносом общих свойств и поведения в основной блок и созданием специальных модификаторов под отдельные случаи (когда обычная кнопка должа вдруг начать вести себя как радиокнопка).

                                  История с тем, как вынести вовне общий код у компонент, которые похожи друг на друга, но не сильно — стара, как мир. В определённый момент (я в этом твёрдо уверен) надо рвать «наследственную связь» и копипастить, потому что поддержание зависимостей со множественным переопределением себя не оправдывает с практической точки зрения — будут сплошные баги и регрессии, которые съедят всё время, которое сэкономит shared code base.
                                • 0
                                  Есть, конечно. Базовые блоки. Копипаста нет, просто блок, который группа, использует в себе как зависимость другой блок. И в случае смены стиля кнопки, к примеру, стиль группы измениться тоже.
                        • +1
                          Отличная статья, спасибо! Давно хотел разобраться с БЭМ и как начать его использовать в своих проектах, желательно без полного стека инструментов — не хватало как раз такого легкоусвояемого материала.

                          Я использую Angular в своем проекте, что можете сказать об удобстве использования БЭМ с этим фреймворком, есть ли какие-то ограничения? Что-нибудь почитать на эту тему или примеры проектов очень бы помогли.
                          • 0
                            Спасибо!

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

                            tech.yandex.ru/events/bemup/18-april-2014/
                            • 0
                              Можете посмотреть мой доклад tech.yandex.ru/events/bemup/17-may-2014/talks/1928/, мы используем Angular. И еще надо взглянуть вот сюда github.com/verybigman/bem-ng.
                              • 0
                                1. может быть глупый вопрос, а у вас верстальщик пишет шаблоны bemhtml?
                                2. как мне писать директивы для ангуляра и при этом использовать шаблоны bemhtml?
                                • 0
                                  1. Да, bemhtml.
                                  2. Есть нюансы в сборке. Мы отделили Angular приложение, как в MEAN стеке, там и пишем директивы. Вьюхи собираются из другой директории и складываются с помощью Gulp. i-bem.js не включается в итоговую сборку скриптов, это искусственное ограничение, чтобы избежать конфликтов.

                                  Ответил на вопрос? Посмотрите еще вот сюда github.com/verybigman/generator-bem
                                  • 0
                                    Спасибо за развернутый ответ.
                                    Такой уровень абстракции с шаблонами несколько ломает представления).
                            • 0
                              Сейчас как раз интересуюсь БЭМ и АНБ. Полный стек не интересует — интерес вызывает наименования классов и файловая структура.
                              Вроде кажется что все просто и понятно, но потом решаешься попробывать на большом проекте, и вот тогда начинаются вопросы.

                              1) По метолологии все блоки, лежат в папке blocks. Но что делать, если блоков становится слишком много? Я конечно понимаю, что можно их ка кто разбить на модули по типу

                              blocks/
                              ..module1/
                              ....block1/
                              ....block2/
                              
                              ..module2/
                              ....block1/
                              ....block2/
                              


                              А как все таки с точки зрения БЭМ решать эту проблему?

                              2) Такие инструменты как SASS дают хорошую возможность. использовать, например, переменные, различного вида хелперы, миксины, наследование. Но, если мы с блоке начинаем юзать что-то из этого, но он же перестает быть независимым и становиться зависимым от контекста. То есть, либо мы нарушаем АНБ, либо пишем кучу повторяющегося кода.
                              Как БЭМ смотрит на эту проблему?

                              • 0
                                1. Можно группировать блоки по смыслу. Например, мы используем группировку по платформам: common.blocks, desktop.blocks, touch.blocks и т.д.

                                2. Блоки могут иметь зависимости, только эти зависимости должны быть явные. Чтобы при необходимости повторно использовать блок, его перенос на другой проект автоматически доставлял все зависимости. См. пример.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое