Предупрежу заранее, что я совершенно не считаю себя экспертом HTML/CSS/JS. Но, как архитектору, мне всегда была интересна организация и систематизация кода в самых разных его проявлениях, в том числе и представленных в виде CSS. Особенно сильно этот интерес был подогрет БЭМом, при первом знакомстве с которым подсознание отреагировало когнитивным дискомфортом. А поскольку БЭМ-стиль в проектах у меня стал появляться все чаще, я почувствовал острую необходимость осмыслить, наконец, свое отношение к организации стилей. Таким образом и появился данный топик-размышление, топик-дискуссия. Я понимаю, что взялся за пограничную задачу, поскольку далеко не всем верстальщикам знакомы тонкости объектно-ориентированного дизайна, а большинство архитекторов не написали ни одного CSS-стиля. И, как результат, мне пришлось неуклюже балансировать, чтобы было понятно всем. Но 'этот риск еще больше подогрел мой интерес к теме :)
Начать я решил с того, что мне было не совсем понятно в БЭМ:
1. Многие считают, что техника априори верна всегда и везде, поскольку за ней стоит Яндекс. Почему то, что подходит крупной компании с гигантским штатом и небольшим количеством однотипных проектов должно так же хорошо работать, скажем, в небольшой команде, которая осуществляет заказную разработку самых разнообразных сайтов? Возьмем в качестве примера подходы из jQueryUI, KendoUI и т.п. Они растиражированы на сотни тысяч проектов и в этом плане имеют гораздо большую зрелость. Причем сам Яндекс на сайте bem.info ясно обрисовывает условия применения, но многие даже не доходят до этого параграфа, ограничиваясь первыми строками и успокоительным: «это же придумали в Яндексе».
2. Почему считается что принудительная контекстная независимость — это хорошо и тут же вводится эта самая зависимость элемента от блока, если пользоваться терминологией БЭМ? Предположим, я хочу, чтобы все кнопки на сайте у меня выглядели не так, как это х��чется автору блока, а в соответствии с единым, продуманным стилем. Если это некоторая стандартная кнопка, то в одном и том же контексте она должна выглядеть одинаково. В другом, как раз, может быть разной. В сайдбаре — поменьше, в теле страницы — побольше, на большом экране — текстом и иконкой, на смартфоне — иконкой. Но если это стандартная кнопка в сайдбаре, то в таких ситуация она должна и выглядеть должна стандартно. Здесь под стандартом подразумевается удачное решение, которое нашли дизайнер вместе с UX-специалистом, а не верстальщик отдельно взятого блока.
Чтобы проиллюстрировать свои сомнения я взял первые попавшиеся формы ввода с сайта Яндекса: создание почтового ящика, регистрация и фидбека.

Не знаю, кто и что увидел на этих картинках, а я вижу полную анархию. Дизайном этих форм занимались, очевидно, не те, кто должен заниматься, а лепили авторы блоков так, как каждый из них это видит. Почему единый стандарт на то, как должны выглядеть поля ввода и кнопки в формах — это плохо?
Яндекс на сайте bem.info пишет: «Каждый новый проект или элемент интерфейса не должны писаться с нуля. Если где-то внутри компании уже выполнялась похожая задача, нужно максимально повторно использовать полученный в результате код. У кода не должно быть контекстной зависимости, его нужно уметь легко переносить в другое место». Давайте посмотрим на пример такого реюзинга.

Два блока логина на одной странице. Если бы это делал я, неправильным способом, то написал бы модуль единожды, а потом, в зависимости от контекста, немного поправил стили, чтобы в сайдбаре он выглядел уменьшенным. Здесь, же я вижу два разных модуля и двух разных авторов. Один считает, что надо «вспомнить пароль», другой предлагает его «напомнить». Первый считает, что линк «зарегистрироваться» не является частью этого функционального блока и вынес его за визуальный контур, второй с ним не согласен. Они расходятся даже в том, как озаглавить этот блок. Автор попап-версии резонного полагает, что пользователь должен осуществить «вход», минималист же хочет, чтобы посетитель сделал «маркет». Они даже реализовывали по-разному, один — табличной версткой, другой — слоями. Повторного использования — ноль. Зато оба использовали БЭМ.
3. Почему отсутствие лаконичности в названиях классов считать преимуществом? И как может нравится это — <div class=«menu__item menu__item_position_first menu__item_state_current»>? В последней верстке, которую я лишил БЭМ объем страницы упал в два раза. Я в данном случае не говорю, что это достаточная причина отказаться от БЭМ и смысл появления этого оверхеда понятен. Просто констатирую, что за такой раздутый синтаксис с низкой энтропией я бы снял балл.
4. Почему нужно отказывать от многих возможностей CSS? Будь то селекторы с использованием идентификаторов, контекстов и т.п.
Первая реакция на БЭМ была такова, что я расшифровал эту аббревиатуру как Бардак Эвентуальный Метастазирующий. Но все эти недовольства попахивали просто очередным частным мнением, которое не очень убеждало меня самого, что уж говорить об убед��тельности для других. И тогда я призвал себя осмыслить саму концепцию классов CSS в архитектурном ключе, как мне привычней.
Начал я системной роли классов. Частное, как правило, является менее важным, чем целое, поскольку последнее — суть их сумма. Так и здесь, участие CSS-классов во взаимодействии с остальной частью системы может быть гораздо важней, чем любые улучшения в области одной только верстки. А участие их здесь весьма серьезное. По сути, названия классов — это единственная крепкая связь между HTML и JS. Основная роль JS, так или иначе, иметь дело с DOM-моделью. А какой самый лучший способ добраться до нужных узлов? Селекторы с участием имен классов. Все остальные варианты не масштабируются. Вы обходите childNodes/parentNode? Завтра там может оказаться враппер и код перестанет работать. Используете названия тегов? Завтра <input> станет <textarea>, <i> станет <em>, <pre> заменят на <code> и скрипты перестанут работать. Имя класса — это тот фундаментальный интерфейс взаимодействия, который мы можем поставить в HTML и использовать в JS не боясь за дальнейшую эволюцию системы.
Я здесь намеренно употребил слово «интерфейс», поскольку хотел провести аналогию с объектно-ориентированными практиками. Надо же как-то отрабатывать заголовок. В свое время Бертран Мейер в рамках разработки языка Eiffel озвучил парадигму проектирования Design by contract. Я не буду сильно углубляться в ее детали, ограничусь только ключевой концепцией. Объекты несут бремя «контрактных» обязательств и взаимодействуют между собой через эти самые контракты. Например, есть некий виджет, который может принимать другие объекты drag'n'drop-ом. Он всем сообщает: «я могу это, для этой цели у меня есть, скажем, функция CanDrop, которой вы передаете в качестве аргумента объект, а я возвращаю логическое значение, принимаю такого типа объекты или нет». Таким образом в его контракте прописано наличие этой функции, ее сигнатура и суть. Системе абсолютно не важно, взял на себя этот контракт виджет для аплоада файлов, дерево с возможностью перетаскивать узлы или это такая продвинутая корзина товаров, куда их можно переносить из каталога мышкой. При операции drag'n'drop-а ей достаточно только знать о том, что некий виджет несет эти контрактные обязательства. И когда вы потащите файл в корзину товаров, она вызовет метод CanDrop корзины получит фейл и просигнализирует вам о невозможности данной операции.
В дальнейшем суть контрактного подхода активно развивалась и большая часть современных паттернов проектирования основывается на использовании интерфейсов объектов. А интерфейс объекта — суть и есть контракт, который перечисляет все методы, которые данный объект может выполнить. Так что речь идет о весьма зрелом и знакомом многим программистам подходе.
Попробую теперь переложить эту идею на HTML+CSS+JS. Представим себе для начала два простых контракта — container и item, они же имена CSS-классов. Первый говорит нам, что он берет на себя обязательства по работе с item. Ему абсолютно все равно, какой за ним стоит тег или DOM-узел. Это может быть элемент списка, пункт меню, закладка на таб-контроле. Он может работать с кем угодно, если этот кто-то готов исполнять контракт item. Таким образом мы укрощаем задачу по принципу «разделяй и властвуй», разбивая на отдельные функциональные области. Работая, например, с меню мы разделяем всё его многообразие функций на те, что отвечают за организацию пунктов меню по принципу container+item, и все остальные.
Для контракта item можем определить некоторую функцию getParent() { return $(this.dom).closest(".container"); }. Для контейнера целую россыпь функций вроде remoteItem, upItem, downItem и т.п. Используя в селекторах только .container и .item вы знаете, что одни и те же функции вы можете использовать для списков, меню, закладок и любых других видов коллекций. Или, другими словами, вы пишите функции по работе со списками и контейнерами один раз, в дальнейшем их просто используете. Если вы добавили новую функцию в свою библиотеку, то она автоматически может быть использована везде, где контейнеры были организованы таким образом. Это замечательно работает в программировании, так почему бы этому принципу не сработать и здесь?
Давайте попробуем экстраполируем этот пример, скажем, на табы.
Интерфейс tabbed берет на себя обязательства предоставить доступ к контейнерам _tabs и _pages. Это значит, что если у вас на руках есть объект, реализующий этот контракт, то вы вправе вызвать методы getTabs и getPages, чтобы получить доступ к соответствующим контейнерам. Про последние мы знаем, что они реализуют контракт container, а значит имеют на руках все необходимые функции для работы с коллекцией закладок, в том числе обрабатывать first/last/odd/even и прочие типовые стили для списков. То есть изобретать заново функцию для удаления таба будет не нужно.
К контейнерам добавился еще один контракт — selectable. Он может брать на себя обязательства по предоставлению функции для определения текущего выбранного элемента, менять выбранный элемент и т.п. Например, функции:
И опять же, эти функции будут одинаково хорошо работать для списков, выпадающих список, панелбаров, слайдеров и всех прочих типов виджетов, где предполагается наличие выбранного элемента, а не только для табов. Когда вы находите и исправляете ошибку в этих функциях, то вы исправляете ее везде.
Если вы, скажем, захотите добавить возможность перетаскивать табы drag'n'drop-ом, то просто добавите контракты drag/drop, что позволит сразу задействовать все те типовые функции, которые были для этой цели уже подготовлены.
Но стоит только написать в БЭМ-стиле tabbed_tabs__item, как краски сразу потускнеют. Ведь весь тот код, который всегда хорошо работал с селектором ".item", для самых разных виджетов, перестал работать. У вас были скины, с самыми различными отображениями табов, но они теперь тоже не работают. Мне могут возразить, что имеют место специальные расширения для того ��е jQuery, которые помогут разобраться со всем этим синтаксическим мусором. Но мне пока не понятно, зачем создавать проблемы, а потом их решать.
Естественно, все эти «контракты», как и интерфейсы в объектно-ориентированном дизайне, должны быть систематизированы и разложены по полочкам. В программировании это зачастую решается за счет использования пространств имен. Но делается это один раз, а потом используется сколь угодно долго и на любом количестве проектов.
На базе таких контрактов гораздо проще ввести внутренние стандарты и реализовать валидаторы, которые будут держать качество кода на постоянном контроле. Это позволит всем участникам процесса, в том числе и вновь подключившимся, мыслить в одном ключе. В начале — императивно, а потом уже по привычке. Ведь как в объектно-ориентированном дизайне контракты не вводятся просто так, а являются следствием продуманного акта, так и в CSS имена классов не должны возникать спонтанно, необдуманно. Ведь БЭМ хоть и пытается контролировать структурный аспект разработки, но совершенно упускает системный. Кто-то табы назовет tabs, кто-то tab-control, иной tab-widget. Например, форма логина у Яндекса из примера в начале статьи называется «b-domik». Это же так мило, назвать ее не login, signup или еще как-нибудь осмысленно, а «би-домик». Вспоминается старое институтское «пи с домиком и пи с душечкой». Верх креатива, но ад для валидации и рефакторинга. Если вы внезапно захотите найти все формы логина и добавить туда новые опции (скажем, идентификацию через какой-нибудь новый социальный сервис), то вам предстоит отловить этот би-домик, узнать, что в почте яндекса он уже зовется b-mail-domik, ссылка «Войти в почту» c титульной страницы уже содержит форму логина с классом b-popupa__wrap. А сколько вам еще подготовлено «открытий чудных»…
Мне кажется, что верстальщики вообще не должны выдумывать имена классов. Обеспечение интерфейсов между HTML и JS должно осуществляться проектировщиками. Они разрабатывают контракты, систематизируют и доносят эту информацию до тружеников HTML/CSS. Это дает и масштабируемость JS-кода, и реюзинг, и рефакторинг, и валидацию в соответствии с корпоративными стандартами, а значит — качество. Мне кажется этого вполне достаточно для того, чтобы был повод поразмышлять.
Под конец замечу, что такие стили достаточно легко и органично описываются в духе LESS/SASS/Stylus-препроцессоров:
Таким образом можно легко собирать и повторно использовать различные скины. Причем, при компиляции все это породит семантически похожие на БЭМ селекторы, поскольку нет никакой существенной разницы между .tabbed ._tabs .item {…} и .tabbed_tabs__item {…}.
Вопросы к БЭМ
Начать я решил с того, что мне было не совсем понятно в БЭМ:
1. Многие считают, что техника априори верна всегда и везде, поскольку за ней стоит Яндекс. Почему то, что подходит крупной компании с гигантским штатом и небольшим количеством однотипных проектов должно так же хорошо работать, скажем, в небольшой команде, которая осуществляет заказную разработку самых разнообразных сайтов? Возьмем в качестве примера подходы из jQueryUI, KendoUI и т.п. Они растиражированы на сотни тысяч проектов и в этом плане имеют гораздо большую зрелость. Причем сам Яндекс на сайте bem.info ясно обрисовывает условия применения, но многие даже не доходят до этого параграфа, ограничиваясь первыми строками и успокоительным: «это же придумали в Яндексе».
2. Почему считается что принудительная контекстная независимость — это хорошо и тут же вводится эта самая зависимость элемента от блока, если пользоваться терминологией БЭМ? Предположим, я хочу, чтобы все кнопки на сайте у меня выглядели не так, как это х��чется автору блока, а в соответствии с единым, продуманным стилем. Если это некоторая стандартная кнопка, то в одном и том же контексте она должна выглядеть одинаково. В другом, как раз, может быть разной. В сайдбаре — поменьше, в теле страницы — побольше, на большом экране — текстом и иконкой, на смартфоне — иконкой. Но если это стандартная кнопка в сайдбаре, то в таких ситуация она должна и выглядеть должна стандартно. Здесь под стандартом подразумевается удачное решение, которое нашли дизайнер вместе с UX-специалистом, а не верстальщик отдельно взятого блока.
Чтобы проиллюстрировать свои сомнения я взял первые попавшиеся формы ввода с сайта Яндекса: создание почтового ящика, регистрация и фидбека.

Не знаю, кто и что увидел на этих картинках, а я вижу полную анархию. Дизайном этих форм занимались, очевидно, не те, кто должен заниматься, а лепили авторы блоков так, как каждый из них это видит. Почему единый стандарт на то, как должны выглядеть поля ввода и кнопки в формах — это плохо?
Яндекс на сайте bem.info пишет: «Каждый новый проект или элемент интерфейса не должны писаться с нуля. Если где-то внутри компании уже выполнялась похожая задача, нужно максимально повторно использовать полученный в результате код. У кода не должно быть контекстной зависимости, его нужно уметь легко переносить в другое место». Давайте посмотрим на пример такого реюзинга.

Два блока логина на одной странице. Если бы это делал я, неправильным способом, то написал бы модуль единожды, а потом, в зависимости от контекста, немного поправил стили, чтобы в сайдбаре он выглядел уменьшенным. Здесь, же я вижу два разных модуля и двух разных авторов. Один считает, что надо «вспомнить пароль», другой предлагает его «напомнить». Первый считает, что линк «зарегистрироваться» не является частью этого функционального блока и вынес его за визуальный контур, второй с ним не согласен. Они расходятся даже в том, как озаглавить этот блок. Автор попап-версии резонного полагает, что пользователь должен осуществить «вход», минималист же хочет, чтобы посетитель сделал «маркет». Они даже реализовывали по-разному, один — табличной версткой, другой — слоями. Повторного использования — ноль. Зато оба использовали БЭМ.
3. Почему отсутствие лаконичности в названиях классов считать преимуществом? И как может нравится это — <div class=«menu__item menu__item_position_first menu__item_state_current»>? В последней верстке, которую я лишил БЭМ объем страницы упал в два раза. Я в данном случае не говорю, что это достаточная причина отказаться от БЭМ и смысл появления этого оверхеда понятен. Просто констатирую, что за такой раздутый синтаксис с низкой энтропией я бы снял балл.
4. Почему нужно отказывать от многих возможностей CSS? Будь то селекторы с использованием идентификаторов, контекстов и т.п.
Первая реакция на БЭМ была такова, что я расшифровал эту аббревиатуру как Бардак Эвентуальный Метастазирующий. Но все эти недовольства попахивали просто очередным частным мнением, которое не очень убеждало меня самого, что уж говорить об убед��тельности для других. И тогда я призвал себя осмыслить саму концепцию классов CSS в архитектурном ключе, как мне привычней.
Design by contract
Начал я системной роли классов. Частное, как правило, является менее важным, чем целое, поскольку последнее — суть их сумма. Так и здесь, участие CSS-классов во взаимодействии с остальной частью системы может быть гораздо важней, чем любые улучшения в области одной только верстки. А участие их здесь весьма серьезное. По сути, названия классов — это единственная крепкая связь между HTML и JS. Основная роль JS, так или иначе, иметь дело с DOM-моделью. А какой самый лучший способ добраться до нужных узлов? Селекторы с участием имен классов. Все остальные варианты не масштабируются. Вы обходите childNodes/parentNode? Завтра там может оказаться враппер и код перестанет работать. Используете названия тегов? Завтра <input> станет <textarea>, <i> станет <em>, <pre> заменят на <code> и скрипты перестанут работать. Имя класса — это тот фундаментальный интерфейс взаимодействия, который мы можем поставить в HTML и использовать в JS не боясь за дальнейшую эволюцию системы.
Я здесь намеренно употребил слово «интерфейс», поскольку хотел провести аналогию с объектно-ориентированными практиками. Надо же как-то отрабатывать заголовок. В свое время Бертран Мейер в рамках разработки языка Eiffel озвучил парадигму проектирования Design by contract. Я не буду сильно углубляться в ее детали, ограничусь только ключевой концепцией. Объекты несут бремя «контрактных» обязательств и взаимодействуют между собой через эти самые контракты. Например, есть некий виджет, который может принимать другие объекты drag'n'drop-ом. Он всем сообщает: «я могу это, для этой цели у меня есть, скажем, функция CanDrop, которой вы передаете в качестве аргумента объект, а я возвращаю логическое значение, принимаю такого типа объекты или нет». Таким образом в его контракте прописано наличие этой функции, ее сигнатура и суть. Системе абсолютно не важно, взял на себя этот контракт виджет для аплоада файлов, дерево с возможностью перетаскивать узлы или это такая продвинутая корзина товаров, куда их можно переносить из каталога мышкой. При операции drag'n'drop-а ей достаточно только знать о том, что некий виджет несет эти контрактные обязательства. И когда вы потащите файл в корзину товаров, она вызовет метод CanDrop корзины получит фейл и просигнализирует вам о невозможности данной операции.
В дальнейшем суть контрактного подхода активно развивалась и большая часть современных паттернов проектирования основывается на использовании интерфейсов объектов. А интерфейс объекта — суть и есть контракт, который перечисляет все методы, которые данный объект может выполнить. Так что речь идет о весьма зрелом и знакомом многим программистам подходе.
Попробую теперь переложить эту идею на HTML+CSS+JS. Представим себе для начала два простых контракта — container и item, они же имена CSS-классов. Первый говорит нам, что он берет на себя обязательства по работе с item. Ему абсолютно все равно, какой за ним стоит тег или DOM-узел. Это может быть элемент списка, пункт меню, закладка на таб-контроле. Он может работать с кем угодно, если этот кто-то готов исполнять контракт item. Таким образом мы укрощаем задачу по принципу «разделяй и властвуй», разбивая на отдельные функциональные области. Работая, например, с меню мы разделяем всё его многообразие функций на те, что отвечают за организацию пунктов меню по принципу container+item, и все остальные.
Для контракта item можем определить некоторую функцию getParent() { return $(this.dom).closest(".container"); }. Для контейнера целую россыпь функций вроде remoteItem, upItem, downItem и т.п. Используя в селекторах только .container и .item вы знаете, что одни и те же функции вы можете использовать для списков, меню, закладок и любых других видов коллекций. Или, другими словами, вы пишите функции по работе со списками и контейнерами один раз, в дальнейшем их просто используете. Если вы добавили новую функцию в свою библиотеку, то она автоматически может быть использована везде, где контейнеры были организованы таким образом. Это замечательно работает в программировании, так почему бы этому принципу не сработать и здесь?
Пример
Давайте попробуем экстраполируем этот пример, скажем, на табы.
<div class="tabbed">
<ul class="_tabs container selectable">
<li class="tab item selected">…</li>
<li class="tab item">…</li>
…
</ul>
<div class="_pages container selectable">
<div class="panel item selected">…</div>
<div class="panel item">…</div>
…
</div>
</div>
Интерфейс tabbed берет на себя обязательства предоставить доступ к контейнерам _tabs и _pages. Это значит, что если у вас на руках есть объект, реализующий этот контракт, то вы вправе вызвать методы getTabs и getPages, чтобы получить доступ к соответствующим контейнерам. Про последние мы знаем, что они реализуют контракт container, а значит имеют на руках все необходимые функции для работы с коллекцией закладок, в том числе обрабатывать first/last/odd/even и прочие типовые стили для списков. То есть изобретать заново функцию для удаления таба будет не нужно.
К контейнерам добавился еще один контракт — selectable. Он может брать на себя обязательства по предоставлению функции для определения текущего выбранного элемента, менять выбранный элемент и т.п. Например, функции:
getSelected: function() {
return $(this.dom).find(".item.selected").first();
},
deselect: function() {
$(this.dom).getSelected().removeClass("selected") ;
},
select: function (item) {
this.deselect(); $(item.dom).addClass("selected");
}
И опять же, эти функции будут одинаково хорошо работать для списков, выпадающих список, панелбаров, слайдеров и всех прочих типов виджетов, где предполагается наличие выбранного элемента, а не только для табов. Когда вы находите и исправляете ошибку в этих функциях, то вы исправляете ее везде.
Если вы, скажем, захотите добавить возможность перетаскивать табы drag'n'drop-ом, то просто добавите контракты drag/drop, что позволит сразу задействовать все те типовые функции, которые были для этой цели уже подготовлены.
Но стоит только написать в БЭМ-стиле tabbed_tabs__item, как краски сразу потускнеют. Ведь весь тот код, который всегда хорошо работал с селектором ".item", для самых разных виджетов, перестал работать. У вас были скины, с самыми различными отображениями табов, но они теперь тоже не работают. Мне могут возразить, что имеют место специальные расширения для того ��е jQuery, которые помогут разобраться со всем этим синтаксическим мусором. Но мне пока не понятно, зачем создавать проблемы, а потом их решать.
Стандарты
Естественно, все эти «контракты», как и интерфейсы в объектно-ориентированном дизайне, должны быть систематизированы и разложены по полочкам. В программировании это зачастую решается за счет использования пространств имен. Но делается это один раз, а потом используется сколь угодно долго и на любом количестве проектов.
На базе таких контрактов гораздо проще ввести внутренние стандарты и реализовать валидаторы, которые будут держать качество кода на постоянном контроле. Это позволит всем участникам процесса, в том числе и вновь подключившимся, мыслить в одном ключе. В начале — императивно, а потом уже по привычке. Ведь как в объектно-ориентированном дизайне контракты не вводятся просто так, а являются следствием продуманного акта, так и в CSS имена классов не должны возникать спонтанно, необдуманно. Ведь БЭМ хоть и пытается контролировать структурный аспект разработки, но совершенно упускает системный. Кто-то табы назовет tabs, кто-то tab-control, иной tab-widget. Например, форма логина у Яндекса из примера в начале статьи называется «b-domik». Это же так мило, назвать ее не login, signup или еще как-нибудь осмысленно, а «би-домик». Вспоминается старое институтское «пи с домиком и пи с душечкой». Верх креатива, но ад для валидации и рефакторинга. Если вы внезапно захотите найти все формы логина и добавить туда новые опции (скажем, идентификацию через какой-нибудь новый социальный сервис), то вам предстоит отловить этот би-домик, узнать, что в почте яндекса он уже зовется b-mail-domik, ссылка «Войти в почту» c титульной страницы уже содержит форму логина с классом b-popupa__wrap. А сколько вам еще подготовлено «открытий чудных»…
Мне кажется, что верстальщики вообще не должны выдумывать имена классов. Обеспечение интерфейсов между HTML и JS должно осуществляться проектировщиками. Они разрабатывают контракты, систематизируют и доносят эту информацию до тружеников HTML/CSS. Это дает и масштабируемость JS-кода, и реюзинг, и рефакторинг, и валидацию в соответствии с корпоративными стандартами, а значит — качество. Мне кажется этого вполне достаточно для того, чтобы был повод поразмышлять.
CSS-препроцессоры
Под конец замечу, что такие стили достаточно легко и органично описываются в духе LESS/SASS/Stylus-препроцессоров:
.tabbed {
…
._tabs {
….
.item {
….
.selected {
…
}
}
}
…
}
Таким образом можно легко собирать и повторно использовать различные скины. Причем, при компиляции все это породит семантически похожие на БЭМ селекторы, поскольку нет никакой существенной разницы между .tabbed ._tabs .item {…} и .tabbed_tabs__item {…}.
