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

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

Мысль интересная, но вообще писать CSS вредно. Человечество уже придумало SCSS и LESS для этих целей. А там можно делать всякие:
.my-mega-widget {
   .disabled {
       //....
   }
}
Не вредно
.button,
.button-disabled {...}

.button-disabled {...}
Ну это же страшно выглядит и сложно сопровождается.
Ведь есть няшные LESS/SCSS с миксинами, переменными, и красивым иерархичным, читабельным кодом.
Имеется ввиду, наверное:

.my-mega-widget {
  &.disabled {
    // ...
  }
}


Или disabled — это вложенный элемент, а не модификатор для самого компонента?
Полагаю, имеется в виду подобное:
.my-mega-widget {
  .button {
    &.disabled {
      // ...
    }
  }
}

Это как раз то самое пространство имен, об отсутствии которого все постоянно плачут и уходят на три буквы.
Что случится если внутри my-mega-widget появится my-another-mega-widget внутри которого будет button?

На button уже будут мачится два селектора: .my-mega-widget .button и .my-another-mega-widget .button, а это не то, чего ожидаешь от композиции компонентов.
Описанная проблема мне ясна.

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

Но таких проектов далеко не большинство. Большинству не нужна эта жесткость, а один и тот же виджет может наоборот требовать разного оформления в зависимости от контекста. И если внутри .my-mega-widget таки понадобится использовать родные стили от .my-another-mega-widget, всегда есть тот же extend, которые пробросит стили и решит все проблемы на уровне приоритетов CSS.

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


На любом сайте, который живет и развивается, компонентый подход оправдан.

Завтра приходит менеджер и просит переставить вот эту штуку сюда, а этот блок вложить вот в этот — не круто говорить в таких случаях «Я так не задумывал! Мне нужно неделю, чтобы все переверстать».
Если на это требуется неделя, значит что-то тут нечисто.
В этом-то и проблема. Когда один компонент влияет на другой и «разное оформление в зависимости от контекста», то просьба менеджера переставить компонент в другое место превращается в игру «угадай, сломается ли что-нибудь при переносе».
И нужно время на то, чтобы разобраться что сломалось и починить.
А если бы сразу писались компоненты, которые ни от чего не зависят, проблемы бы даже не возникло.
Популярный аргумент. Но вообще-то, принцип области ответственности для компонент никто не отменял. Чем конкретнее компонент — тем лучше. Это значит, что он не принимает внутрь посторонии компоненты, если конечно изначально не было это предусмотренно, тогда конечно и css будет другим и разметка. И более того, хорошо когда композиция компонент является плоской, а не вглубину.
НЛО прилетело и опубликовало эту надпись здесь
Проблема в том, что завтра это превратится в

.my-mega-widget {
  & > .button {
    & > .text {
      & > .icon {
        ...
      }
    }
  }
}


А послезавтра потребуется добавить обертку для кнопки и селектор непосредственного потомка перестанет работать.
НЛО прилетело и опубликовало эту надпись здесь
Кажется, и так и так — сложнее, чем локальный скоуп для каждого компонента по дефолту.
НЛО прилетело и опубликовало эту надпись здесь
Вот тут как раз хороший пример, почему изолировать нужно не только селекторы, но и свойства с помощью `all: initial` и других PostCSS-плагинов.
С чего это будет матчится button?
если одна кнопка
.my-mega-widget .button {}
а вторая совсем в другом неймспейсе
.my-another-mega-widget .button {}
<style>
.mega-widget .button { color: red;}
.my-another-mega-widget .button { border: solid 1px red;}
</style>
<div class="mega-widget"><button class="button">mega-widget</button></div>
<div class="my-another-mega-widget"><button class="button">my-another-mega-widget</button></div>


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

<div class="mega-widget">
  <button class="button">mega-widget</button>
  <div class="my-another-mega-widget">
    <button class="button">my-another-mega-widget</button>
  </div>
</div>


Уникальные имена классов для каждого элемента избавляют от таких казусов. В БЭМ это решается неймингом, а в CCS-модулях — автоматически, за счет локального скоупа.
Чтобы не дублировать http://habrahabr.ru/post/270075/?reply_to=8641825#comment_8641835
Одно дело когда какие-то стили из разряда color идут дальше по дереву и другое, когда специально прописываешь каскады и попадаешь в вышеописанный случай, где верстка кнопок ломается
CSS Modules — это не обычный CSS ;). Это PostCSS, так что подключите postcss-nested и у вас будет та же вложенность.
Так-то, можно писать на том же LESS \ SASS, а потом уже получившуюся CSSку грузить.
Да так тоже можно — но postcss-nested будет быстрее (1 раз парсить) и проще настраивать (не будет проблем с путями карт кода).
CSS прекрасен своей простотой. Зачем превращать его в язык программирования?

А по поводу примера, селекторы типа .my-mega-widget с ростом кодовой базы становятся довольно длинными и работать с ними не всегда удобно.
Я бы сказал, тут интерес другой момент. В эру компонентного подхода можно довольно лаконично описывать состояние компонента без необходимости добавлять какой-то префикс, который гарантирует уникальный неймспейс. Например, с помощь CSS Модулей, туже самую кнопку можно описать как-то так:

.normal {...}
.disabled {...}
.error {...}
.progress {...}
В итоге после сборки мы получим все те же .button.error в стилях? По сути ничего от button_error не отличается
Да, на выходе результат схожий, но с исходными файлами становится чуть проще работать за счет подобной автоматизации. Также уменьшаются возможные коллизии, так как задача генерации уникальных селекторов перекладывается на роботов.

Реже возникает необходимость увеличивать специфичность селекторов, так как можно свободно писать .title и не думать о последствиях.
Зря не упомянули postcss-autoreset или postcss-initial. Изоляция селекторов — только малая часть. Ещё есть большая проблема глобальных ресетов и наследования свойств. Эти плагины их как раз решают.

Ну а так как CSS Modules тоже написан на PostCSS, то даже парсить два раза не придётся.

На Front Talks я более подробно рассказывал, как использовать PostCSS для изоляции стилей: www.youtube.com/watch?v=XJaJqLVaR-c
Видео приватное
Извините, может что-то не понял, но чем это кардинально отличается от бэма, не считая того, что для модификатора не надо писать название изначального блока? (То есть button button_loading button_disabled превратится в button-disabled button-loading)
Так это и есть просто автоматический БЭМ — не надо ни о чём думать. Примерно как Автопрефиксер и примеси для префиксов.
Там, правда, есть ещё один плюс — в конец селектора добавляется случайная строка. Но это важно только для разработки с виджетов для стороннего сайта, где может произойти конфликт имени блока.
Я как раз хотел противопоставить в каком-то смысле БЭМ и CSS-модули: есть одна и та же задача — решать ее можно по-разному.

Как верно отметил Iskin, плюс CSS-модулей в том, что «не надо ни о чем думать».
Видео доклада Павла Ловцевича с WSD в Минске.
Спасибо, обновил ссылку на доклад
А что если, вместо БЭМ и модулей принять соглашение о том, что каждый виджет должен быть изолирован своим «главным» классом?

.awesome-module {
	.button {
		&.disabled {
			//...
		}
	}
}

.cool-module {
	.button {
		&.disabled {
			//...
		}
	}
}


Мне нравится идея изоляции CSS, но я не понимаю, зачем такие костыли.
А теперь представьте, что у вас cool-module расположен внутри awesome-module. Тогда стили внутренних элементов будут накладываться друг на друга.
Действительно, такая изоляция может работать, но только для атомарных компонентов: когда мы уверены, что внутри ничего не появится (того, что мы не задумывали).

Во всех остальных случаях необходимо обеспечить, чтобы селекторы элементов одного блока не мачились на вложенный, потому что сам по себе селектор .cool-module .button не обеспечивает этого (будет мачится на все .button внутри, даже если это уже кнопка из другого, вложенного, блока)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации