Комментарии 52
1) Взял проект.
2) Перевёл на БЭМ.
the end.
Если говорить о БЭМ и моем проекте, то у меня многие из используемых повторно блоков генерируется соответствующими классами, стили и клиентские скрипты разнесены по отдельным маленьким файликам. Блоки легко и удобно можно добавлять, изменять и переносить из проекта в проект, они не влияют друг на друга. Т. к. я как раз и старался приблизиться к компонентному подходу. Использовал БЭМ, потому как не нашел ничего лучше.
На самом деле, сколько статей я не читал про БЭМ, везде одни и те же комментарии и ответы на них. Думаю, чтобы понять преимущество (не совершенство, а преимущество со всеми его недостатками) таких вещей, как БЭМ, над их отсутствием, необходимо сперва в полной мере ощутить недостатки «традиционного подхода».
Полимер когда-то смотрел — не понравился. Сейчас еще раз открыл, глянул верстку их семпла-магазина:

Это читабельнее моей верстки? По-моему их страница намного проще, а верстка значительно сложнее.

Хотите сказать, что «menu__group-title sub-title» удобнее и лучше читается, чем пример выше?
На bem.info в «Основных понятиях» сказано буквально следующее: «Блок — логически и функционально независимый компонент страницы, аналог компонента в Web Components. Блок инкапсулирует в себе поведение (JavaScript), шаблоны, стили (CSS) и другие технологии реализации.»
<button class="buttons__button button button--positive" type="button">Send</button>
— настоящая победа синтаксиса БЭМ над здравым смыслом и чувством меры.
У меня была возможность сравнить (и, при желании, она есть и у вас) оба подхода, т. к. я решил переходить на БЭМ имея уже крупный и рабочий проект. В процессе я получил удовольствие, избавился от дублирования, получил совершенно формализированную и строго структурированную верстку и стили. У меня больше нет ощущения, что это вышло из под моего контроля. Но мне интересно, какую альтернативу вы предлагаете?
Что касается синтаксиса для модификаторов, то я указал, что выбрал один из альтернативных вариантов, который, кстати, приведен на сайте bem.info. Мне он понравился больше. Там же описаны и булевые модификаторы, которые компактнее стандартных и не менее (даже более, как по мне) читабельные.
Мне жутко не нравится БЭМовские селекторы, поэтому я использую смесь из camelCase и kebab-case вида 'блок-элемент-модификатор'.
.tableView-cell {}
.tableView-cell-selected {}
.userList-item {}
.userList-item-deleted {}
А так как CSS регистрочувствителен, то никаких проблем с этим нет. Так же иногда я прибегаю к модификаторам с префиксом в виде дефиса.
.tableView-row.-selected {}
В стилях такие модификаторы сами по себе никогда не используются, только в сочетании с основным классом, что позволяет избежать путаницы.
Чистое ИМХО, но класический БЕМ выглядит перегруженным, и при написании, хоть и есть логика в именовании компонентов, но доставляет больше неудобств, чем ощущение 100% полезности. Склоняюсь к использованию более наглядных методов, которые ближе к CSS:
- Разбивка компонентов на файлы
BlockName.scss
- Использование в этом файле префикса
.BlockName
для всех классов (scope) - Использование
.BlockName.is-modifier
в качестве модификатора - Все дочерние элементы
.BlockName-element.is-modifier
Пример: .TopNav-item.is-active
выглядит по-моему лучше, нежели .top-nav__item .top-nav--is-active
.
Но да, нужно признать, это все вариации на тему БЭМ.
По поводу модификаторов, на каком-то старом докладе про бэм задали вопрос докладчику: «зачем использавать .top-nav__item .top-nav--is-active, если можно .top-nav__item.is-active?» Так смешно было, докладчик ушёл от ответа мотивировав тем что не понял вопроса, потому как не знал разницу между .class1 .class2 и .class1.class2 )))
.BlockName > тег
— во-первых как написал DmitrySikorsky это не-гибко, во-вторых производительность этих селекторов ниже. В-третьих, если применять SCSS — это превращается во что то структурированное:
// TopNav.scss
.TopNav {
&-item {
&.is-active { }
}
&-element { }
}
не хочу ничего слишком специфического и стороннего использоватьто почему бы не вот так:
// .TopNav.scss
.container {
}
.item {
&_active {
composes: item; //можно и без этого, тогда на элемент нужно вешать оба класснейма
}
}
//TopNav.jsx - не обязательно React, можно заимпортить где угодно
import theme from './TopNav.scss';
export const TopNav = props => ({
<nav className={css.container}>
<a className={css.item}></a>
<a className={css.item_active}></a>
</nav>
});
Вы получаете инкапсуляцию стилей, автогенерацию класснеймов и отсутствие коллизий.
В зависимости от настроек бандлера, класснеймы могут быть вот такие: .TopNav__container, .TopNav__item, .TopNav__item_active. Дополнительно можно добавить небольшой хэш (5-6) символов в конец.
По поводу гибкости, как я написал выше, компонент монолитен, переноси куда хочешь. Хочешь взять часть из компонента — будь добр сверстай по новому, поэтому компоненты делать надо небольшими.
И потом в будущем при переносе компонента в другой проект, даже если имя корневого класса совпадёт с каким-то уже существующим классом в проекте — достаточно будет только изменить один раз это имя в разметке и стилях, и всё станет на свои места, и внутрянка компонента не поломается благодаря селектору >.
Зато какая чистота в разметке — любо дорого посмотреть))
То есть вместо:
<div class="NavBar">
<button class="NavBar-item is-active">...</button>
</div>
Вы используете:
<div class="NavBar">
<button>...</button>
</div>
И стили:
.NavBar {
> button {
&.is-active { }
}
}
?
Тогда если вдруг нужно использовать вместо <button />
например <a />
, нужно не только менять разметку, но и лезть править стили?
<div class="NavBar">
<button class="NavBar-item"></button>
<div id="а_мало_ли" class="NavBar-sub">
<button class="NavBar-item"></button>
</div>
</div>
Как быть?
>
уже не спасет.NavBar > div > button
Но тогда что делать, если у нас несколько кнопок на одном уровне вложенности, а внешнее оформление у них разное? Придется все-равно использовать класс, либо как-то псевдоклассом по индексу идентифицировать. Это очень жестко.
Что касается двух уровней вложенности > >, то конечно я так не делаю. Это как раз первый признак того что надо добавить класс и делать ещё один компонент, более маленький.
С таким подходом ведём несколько проектов, которые постоянно изменяются, и компоненты кочуют из одного в другой. Также это помогает больше уделить внимание семантике разметки, поскольку банально удобнее читается.
Пример:
Кнопка с свг-иконкой и текстом в спане (допустим без спана обойтись нельзя). Определяем что это всё будет компонентом. Даём какой-нибудь корневой класс, например .main_button. Так вот зачем мне дополнительно давать классы свг и спану, если я могу написать так:
.main_button{
...
...
...
&>span{...}
&>svg{...}
&:hover,
&:focus{...}
&:active{...}
&:disabled{...}
&.js_showSpinner{....}
@media при необходимости
}
И это будет полноценный компонент кнопки, который не следует потрошить, а взять и копипастнуть куда надо.
Судя по всему проекты — это сайты, где нет большого количества сторонних компонентов и плагинов, и команда не сильно большая.
Но если есть комопонент, и ты его создатель, а вас еще 20+ человек на проекте и каждому необходимы какие то изменения в компонентах, тогда ты становишься на проекте узким горлышком, потому что только ты можешь делать измененя в компонентах, потому что это твоя отвтетственность.
Создатель хорошо сказано. Компонент свёрстан, это моё произведение труда так сказать. Я ожидаю, что им будут пользоваться разработчики, а не будут его ломать. Потому что ломать его — это должно прийти «распоряжение» от проектировщика интерфейса, например поменялось состояние или поведение.
И правильно, в моей зоне ответственности, чтобы компонент соответствовал дизайнерским ожиданиям, и не ломался от наполнения любыми данными от разработчиков, был так сказать железобетонным. Т.е. разрабы наполняют компонент, а не изменяют его. Они пишут бизнес логику, а логику микровзаимодействий создют верстальщик и дизайнер.
И да, если вдруг разработчику нетерпится что- то изменить в разметке компонента, он это делает но и без проблем может найти место в стилях по корневому классу компонента чтоб дописать их. Если влом лезть в стили, может прямо инлайново написать их как-нибудь, верстальщик за ним подправит потом, ничего плохого в этом не вижу. Но это редкая ситауция, потому как «архитектура» вёрстки продумывается достаточно хорошо.
И никаким узким горлышком вёрстка у нас никогда не была. Bottle neck — это как правило сам бизнес..))
button--positive, button--negative и button--neutralВ данном случае использовать булевы модификаторы плохо, потому что это даёт возможность добавить блоку все три эти модификатора одновременно.
Тут лучше использовать модификатор ключ-значение, потому что фактически может быть только один из этих модификаторов у конкретной кнопки, т.е. кнопка может быть или positive, или negative, или neutral.
Рассматривайте это как аналог атрибута type у input. Значение конкретного типа определяет каким именно будет этот input. Тут логика точно такая же.
не понимаю зачем все так усложнять, с каждым днем процесс верстки все сложнее и сложнее, теперь толком не поговоришь с человеком который считает себя верстальщиком, т.к. подходы к работе иные и порой не понимаешь что тебе человек говорит, а на выходе получается тоже самое что и у тебя
Мне казалось, что я использую БЭМ, а оказалось, что только казалось. Прочитал и как-то всё по полочкам разложилось.
В общем, спасибо за статью!
Как я проект на БЭМ переводил… и перевел