Войти с помощью github
Форум /

По мотивам обсуждения в твиттере с подачи @delaz, решили написать пост и собрать еще вопросов и тем для разъяснения, которые в будущем планируем добавить в раздел про методологию.

Что у нас получилось?

  1. БЭМ — это не про префиксы.
  2. БЭМ — это не про длинные названия классов.
  3. Нельзя использовать элементы элементов в нейминге.
  4. Миксы.
  5. БЭМ не запрещает каскад (но и не приветствует).
  6. Как понять, когда делать блок, а когда — элемент.

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

«БЭМ — это длинные имена классов. b-button — это длинно!»

Отвечаем: БЭМ не навязывает префиксы. Чтобы писать хорошо поддерживаемый и реиспользуемый код, префиксы совершенно не нужны. Исторически они появились в переходный период для того, чтобы отличать новый код, написаный по БЭМ, от старого. Со временем мы от них отказались. Если посмотреть в код, можно увидеть, что префиксов там нет.

«А как же префикс js- или i- для блоков без визуального представления?»

Когда-то можно было сверстать сайт практически без JS-кода. Сейчас большая часть блоков имеет JS-представление. Глядя на текущую ситуацию мы поняли, что нет нужды как-то отличать технологии реализации блока на уровне нейминга. Посмотрите, к примеру, на Web Components. Объективно необходимости в префиксах нет, но каждый волен выбирать, что ему, проекту или команде удобнее и/или привычнее.

«Префиксы — ладно. А просто длинные названия блоков?»

В этом и похожих случаях вы можете использовать классы типа btn вместо button. Это никак не помешает вам разрабатывать по БЭМ. Все как с названием переменных в JS: context, ctx или c. Но помните, вам, вашим коллегам и тем, кто будет разрабатывать и поддерживать проект после вас это предстоит читать, понимать и с этим работать ;)

Остается вопрос про неймспейсы — мы пишем имя блока перед именем элементов (button__icon) и модификаторов (button_active).

Если декомпозировать «проблему», можно выделить 2 потенциальных минуса:

  • Результирующий код, который приходится гонять по сети, весит больше. Тут на помощь приходит gzip, который отлично жмет повторяющиеся последовательности и сводит минус на нет.
  • Приходится больше кнопок нажимать на клавиатуре. Здесь помогают автокомплит в редакторе и инструментарий, который автоматически добавляет префиксы (CSS-препроцессоры и шаблонизаторы). Когда вы видите эти два минуса и больше ничего кроме них, мы предлагаем подумать и выбрать, что важнее — время, необходимое на нажатие клавиш, или время, затраченное на обдумывание архитектуры. Во втором случае БЭМ как раз очень сильно помогает. А первое легко автоматизировать не в урон проекту.

И тогда, благодаря неймспейсам, будет решено следующее:

  1. Исчезнет опасность случайно «задеть» внутреннее устройство блока. Мы получим аналог скоупа в JS, но для CSS. Для этого в Web Components придумали Shadow DOM, но в действительности простого добавления имени блока достаточно, чтобы получить тот же результат без лишних телодвижений.
  2. С первого взгляда на любой класс, хоть в CSS, хоть в HTML, хоть в любой другой технологии реализации блока, мы тут же поймем, к какому блоку он относится и какую задачу решает. Сравните: active (на что повлияет этот класс?) VS. input_active или item VS. nav__item.

Да. И к тому же не по БЭМу :)

Неймспейсом служит только имя блока. А отражать вложенность в именах элементов не нужно. Это не только длинно, но еще и не позволит при повторном использовании блока в другой ситуации (или просто при рефакторинге) легко вынуть один элемент из другого. Плоская структура касается не только нейминга, но и расположения кода на файловой системе:

nav/
    __item/
        nav__item.css
    __link/
        nav__link.css

Для выражения вложенности вполне достаточно DOM-дерева:

<ul class="nav">
    <li class="nav__item">
        <a class="nav__link"></a>
    </li>
</ul>

Тут нам на помощь приходят миксы — возможность смешать на одном DOM-узле несколько блоков (или элементов/модификаторов) одновременно.

Предыдущий пример вполне может выглядеть так:

<ul class="nav">
    <li class="nav__item">
        <a class="link nav__link"></a>
    </li>
</ul>

При этом все общее, что есть у всех ссылок на проекте, будет описано в блоке link, а особенности, присущие только ссылке внутри nav — для nav__link.

  1. Это несемантично. А если там в будущем окажется не ссылка вовсе?
  2. Во-вторых, это влечет за собой дополнительные сложности, ведь каскад затронет и вложенные сущности. Например, если в будущем вы захотите усложнить архитектуру или добавить выпадающее меню.
  3. Наконец, структура может поменяться и nav__item совсем исчезнуть.

    «Получается, что в каскадных таблицах стилей нельзя использовать каскад?»

Можно. Но нужно понимать, какие последствия это влечет. Например, каскад уместен, чтобы менять элементы в зависимости от состояния блока (.nav_hover .nav__link { text-decoration: underline; }) или, скажем, темы (.nav_theme_islands .nav__item { line-height: 1.5; }).

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

«Как в принципе отличать, где блок, а где элемент?»

Если хочется переиспользовать кусок кода вне контекста родителя — это точно блок. Если кусок кода не имеет смысла без родителя — это скорее всего элемент. Аналогией служит Shadow DOM в Web Components.

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

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

Очень ждем ваших комментариев!