Как стать автором
Обновить

Комментарии 52

Как я проект на БЭМ переводил… и перевел

1) Взял проект.
2) Перевёл на БЭМ.

the end.
Почему для большого и сложного модульного проекта Вы выбрали устаревший и кривой костыль в виде БЭМ'а, а не компонентный подход, который сам собой напрашивается для решения подобных задач?
НЛО прилетело и опубликовало эту надпись здесь
Если вы про Web Components, то несколько лет назад я читал о том, что за ними будущее. Сейчас за ними, возможно, все так же будущее, но не настоящее.

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

На самом деле, сколько статей я не читал про БЭМ, везде одни и те же комментарии и ответы на них. Думаю, чтобы понять преимущество (не совершенство, а преимущество со всеми его недостатками) таких вещей, как БЭМ, над их отсутствием, необходимо сперва в полной мере ощутить недостатки «традиционного подхода».
Уже давно настоящее, а не будущее. Взять тот же Polymer Project — поддержка всеми браузерами в т.ч. IE 11+. React, Angular 2 — так же компонентный подход. И все они позволяют инкапсулировать стили.
Мне нужна максимально простая реализация, в которой максимально просто разобраться, не требующая ничего стороннего. Как минимум потому, что моя цель — чтобы над проектом работали и другие люди.

Полимер когда-то смотрел — не понравился. Сейчас еще раз открыл, глянул верстку их семпла-магазина:



Это читабельнее моей верстки? По-моему их страница намного проще, а верстка значительно сложнее.
Вы смотрите не верстку, у уже отработавший код и т.к. Ваш браузер (ie/edge судя по ужасному шрифту) полноценно не поддерживает web components, используется полифил. Естественно при верстке всего этого нет и да, она гораздо читабельнее чем БЭМ.



Хотите сказать, что «menu__group-title sub-title» удобнее и лучше читается, чем пример выше?
Повторюсь, мне не нравится необходимость использовать большую стороннюю либу для этой цели, поэтому я даже не стану рассматривать такой вариант. Ее мало кто знает и используют, а голый CSS знают почти все. Когда web components станут стандартом, вполне возможно, я напишу новую статью.
Попробуйте на Object Oriented CSS. Он с точки зрения понятности, рациональности и оптимизации гораздо лучше и читабельнее чем БЕМ.
Я отдал предпочтение именно БЭМ, т. к. многие крупные проекты используют его (чаще, конечно, собственные имплементации этой концепции). Но за ссылку спасибо.
Есть подозрение, что под словом «БЭМ» вы понимаете что-то свое, если противопоставляете компонентному подходу.

На bem.info в «Основных понятиях» сказано буквально следующее: «Блок — логически и функционально независимый компонент страницы, аналог компонента в Web Components. Блок инкапсулирует в себе поведение (JavaScript), шаблоны, стили (CSS) и другие технологии реализации.»
<button class="buttons__button button button--positive" type="button">Send</button>

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

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

Что касается синтаксиса для модификаторов, то я указал, что выбрал один из альтернативных вариантов, который, кстати, приведен на сайте bem.info. Мне он понравился больше. Там же описаны и булевые модификаторы, которые компактнее стандартных и не менее (даже более, как по мне) читабельные.
НЛО прилетело и опубликовало эту надпись здесь
Я понял, что вы имеете в виду насчет модификаторов. Возможно действительно стоило пояснить, что они все имеют общий смысл, таким образом. Спасибо!
Писал выше, что не хочу ничего слишком специфического и стороннего использовать, чтобы не повышать порог вхождения в проект. Если честно, мне и не нравится ничего, связанного с HTML/CSS, кроме голого HTML и CSS. Но вот БЭМ пришлась по душе.
Мне кажется, со временем, человек, который занимается версткой, приходит к чему-то похожему на bem, лично у меня так и вышло.

Мне жутко не нравится БЭМовские селекторы, поэтому я использую смесь из camelCase и kebab-case вида 'блок-элемент-модификатор'.


.tableView-cell {}
.tableView-cell-selected {}
.userList-item {}
.userList-item-deleted {}

А так как CSS регистрочувствителен, то никаких проблем с этим нет. Так же иногда я прибегаю к модификаторам с префиксом в виде дефиса.


.tableView-row.-selected {}

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

Я так понимаю, вы используете +- то же самое, но с немного другим синтаксисом. Думаю, БЭМ можно как раз и рассматривать как «референсную» методологию, наталкивающую на правильные мысли. Главное не в конкретной реализации и даже не в конкретной методологии, а в ее наличии и грамотной имплементации.

Еще забыл упомянуть двубуквенный префикс для переиспользуемых css-библиотек: my-tableView-row.

Вы удивитесь, но среди предлагаемых на официальном сайте вариантов нейминга в том числе присутствует camelCase.

Вы правы – удивлюсь ) Раньше этого не было.

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


  • Разбивка компонентов на файлы BlockName.scss
  • Использование в этом файле префикса .BlockName для всех классов (scope)
  • Использование .BlockName.is-modifier в качестве модификатора
  • Все дочерние элементы .BlockName-element.is-modifier

Пример: .TopNav-item.is-active выглядит по-моему лучше, нежели .top-nav__item .top-nav--is-active.
Но да, нужно признать, это все вариации на тему БЭМ.

Видите, а я наоборот нахожу синтаксис наглядным и удобным. Что поделать — страдаю перфекционизмом, строгая формализация, последовательность и единообразие для меня важнее наличия большего количества классов и немного странного синтаксиса. Хотя ваш подход в своей сути это то же самое.
Поддерживаю. Сам примерно так и пишу. Но к элементам внутри компонента обращаюсь через .BlockName > тег {....} или .BlockName:nth-child(){....}, не засоряя разметку классами. Т.е. класс имеет только компонент, а не все абсолютно все теги в документе. Этот корневой класс компонента создаёт как бы область видимости для всех вложенных элементов.

По поводу модификаторов, на каком-то старом докладе про бэм задали вопрос докладчику: «зачем использавать .top-nav__item .top-nav--is-active, если можно .top-nav__item.is-active?» Так смешно было, докладчик ушёл от ответа мотивировав тем что не понял вопроса, потому как не знал разницу между .class1 .class2 и .class1.class2 )))
Боюсь, в таком случае вы будете вынуждены изменять CSS при каждом изменении HTML и наоборот. Такая жесткая привязка к тегам и уровню вложенности превращает верстку в монолит, который ломается при любом изменении. Также, например, если вы сделали крупный блок, а затем в другом месте вам понадобился его кусок, то вам придется его переверстывать, т. к. просто скопировать и вставить его туда не выйдет, т. к. он полностью привязан к своему контексту.
Вот именно в монолит, только не вёрстка превращается в монолит, а компонент, который можно переносить только целиком. Другое дело, что именно обзывать компонентом/блоком; понятное дело что не кусок разметки на несколько экранов.

.BlockName > тег — во-первых как написал DmitrySikorsky это не-гибко, во-вторых производительность этих селекторов ниже. В-третьих, если применять SCSS — это превращается во что то структурированное:


// TopNav.scss

.TopNav {
  &-item {
    &.is-active { }
  }
  &-element { }
}
Раз уж мы за scss и отходим от
не хочу ничего слишком специфического и стороннего использовать
то почему бы не вот так:
// .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) символов в конец.
Прошу прощения за опечетку,
import css from './TopNav.scss';
как раз селектор > и даёт мне уверенность, что всё будет без проблем в будущем при переносе компонента в другое место. Что касается производительности селекторов — то это какой-то боян или миф, сколько можно про это говорить на каждом шагу, хоть кто-то делал реальные замеры (на реальных проектах, а не на синтетике в 1000000 тегов), и возможно ли это впринципе?

По поводу гибкости, как я написал выше, компонент монолитен, переноси куда хочешь. Хочешь взять часть из компонента — будь добр сверстай по новому, поэтому компоненты делать надо небольшими.

И потом в будущем при переносе компонента в другой проект, даже если имя корневого класса совпадёт с каким-то уже существующим классом в проекте — достаточно будет только изменить один раз это имя в разметке и стилях, и всё станет на свои места, и внутрянка компонента не поломается благодаря селектору >.

Зато какая чистота в разметке — любо дорого посмотреть))

То есть вместо:


<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>


Как быть? > уже не спасет
Думаю, подразумевается 2 >
.NavBar > div > button


Но тогда что делать, если у нас несколько кнопок на одном уровне вложенности, а внешнее оформление у них разное? Придется все-равно использовать класс, либо как-то псевдоклассом по индексу идентифицировать. Это очень жестко.
Ну то есть стили гвоздями прибиваются к верстке. Да уж, удобно…
Если вместо кнопки поменять на ссылку, то это уже изменение разметки блока, т.е. если ты лезешь в блок/компонент — то буть добр и стили подкорректируй, потому что по сути создаётся новый компонент. А моя идея компонента, чтоб можно было переносить его куда угодно, а не изменять. Ведь суть какая — сверстать один раз и пользоваться в будущем. Почему это вдруг менять кнопку на ссылку — это можно, это нормально, а вот уже в стили лезть чтоб подправить за собой — считается плохо? Ведь раз лезешь в кишки компонента — значит берёшь на себя ответственность за его новое состояние и поведение. Поэтому чтоб такого не было — и имеет смысл делать их небольшими.

Что касается двух уровней вложенности > >, то конечно я так не делаю. Это как раз первый признак того что надо добавить класс и делать ещё один компонент, более маленький.

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

Пример:
Кнопка с свг-иконкой и текстом в спане (допустим без спана обойтись нельзя). Определяем что это всё будет компонентом. Даём какой-нибудь корневой класс, например .main_button. Так вот зачем мне дополнительно давать классы свг и спану, если я могу написать так:

.main_button{
    ...
    ...
    ...
    &>span{...}

    &>svg{...}

    &:hover,
    &:focus{...}

    &:active{...}

    &:disabled{...}

    &.js_showSpinner{....}

    @media при необходимости
}


И это будет полноценный компонент кнопки, который не следует потрошить, а взять и копипастнуть куда надо.

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


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

Верно — сайтики и команда небольшая.

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

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

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

И никаким узким горлышком вёрстка у нас никогда не была. Bottle neck — это как правило сам бизнес..))
Смотреть приятно, а производительность ваша снижается, командная работа затрудняется, любые изменения все ломают и нужно лезть в CSS и менять все теги-вложенности. Если проект постоянно находится в состоянии изменения (как большинство живых проектов), использование такого подхода является плохой идеей.
button--positive, button--negative и button--neutral
В данном случае использовать булевы модификаторы плохо, потому что это даёт возможность добавить блоку все три эти модификатора одновременно.

Тут лучше использовать модификатор ключ-значение, потому что фактически может быть только один из этих модификаторов у конкретной кнопки, т.е. кнопка может быть или positive, или negative, или neutral.

Рассматривайте это как аналог атрибута type у input. Значение конкретного типа определяет каким именно будет этот input. Тут логика точно такая же.
Можете привести пример, как избежать одновременного добавления этих модификаторов?
Использовать шаблонизатор, который знает, что нельзя на одном DOM-узле создавать классы одного и того же модификатора с разным значением.

Например, BEMHTML.
Согласен, выше уже писали, правильнее будет button--type_positive.

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

В нашей сфере постоянное обучение и развитие является необходимостью. Иначе, как вы сами написали, к сожалению, будет не о чем говорить с другими специалистами. Что касается получения на выходе того же самого, то это лишь внешне то же самое. Рекомендую, если интересно, почитать о БЭМ и других методологиях, чтобы глубже разобраться в причинах их необходимости. Опять же, в одиночку особого смысла ни в чем таком нет, т. к. вы сами копаетесь в своем проекте. А вот в командной работе все недостатки очень быстро становятся очевидными.
У всех амбиции зашкаливают и принуждают применять методологии вместо того чтобы просто работать…
Дело не в амбициях. Методология помогает выстроить процесс, а если у вас команда (иногда еще и распределенная), то «просто работа» без методологии заведет вас в тупик
Полсотни комментариев, а автору спасибо за статью никто не сказал…
Мне казалось, что я использую БЭМ, а оказалось, что только казалось. Прочитал и как-то всё по полочкам разложилось.
В общем, спасибо за статью!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории