bem-site / bem-forum-content-ru

Content BEM forum for Russian speak users
MIT License
56 stars 6 forks source link

Мысли о модульном и компонентном CSS #1268

Open tenbits opened 7 years ago

tenbits commented 7 years ago

Уважаемые бэмчане,

не сочтите за оффтоп, но хотелось бы услышать ваше мнение. Angular2 и Vue, например, имитируют scoped css через присваивание уникального атрибута всем тегам и добавление его же к селекторам в css. Возникла идея сделать эти трансформации приближенными к бэм методологии. Представьте, что у нашей компоненты шаблон и стили такие:

<section class='product'>
    <header class='title'>
        Foo 
        <span class='hint'></span>
    </header>   
</section>

.product { /* ... */ }
.product .title { /* ... */ }
.product .title .hint { /* ... */ }

Тогда пропустив шаблон и стили через наш преобразователь получим следующее:

<section class='product_ABC product'>
    <header class='product_ABC__title title'>
        Foo 
        <span class='product_ABC__title_hint hint'></span>
    </header>   
</section>
.product_ABC { /* ... */ }
.product_ABC__title { /* ... */ }
.product_ABC__title_hint { /* ... */ }

Принцип прост, по возможности заменить и сделать стили плоскими. Сохранить изначальный селектор Элементов и пройтись по шаблону Добавив новые имена классов. Изначально селекторы всегда вида: BLOCK(…modifiers) ELEMENT(…modifiers) … . Модификаторы мы не изменяем. В следующем примере селектор плоским сделать мы не можем, так как он зависит от состояния родителя:

.product.active .title {}

.product_ABC.active .product_ABC__title { }

Плюсы данного подхода:

Недостатки:

Дополнительно:

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

tadatuta commented 7 years ago

Я так и не понял плюсов:

Разработка блока/компоненты не зависит от инструментария, как Css Modules, например

Не зависит от CSS Modules, но зависит от некоего кастомного преобразователя, который решает аналогичную задачу.

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

То ли нет коллизий и есть проблема с поиском, то ли нет проблемы с поиском, а значит есть вероятность коллизий как минимум в JS.

Все селекторы максимально плоские - хорошо для производительности Минимальная специфичность селекторов - хорошо для переопределения

Следование БЭМ-методологии само по себе сохраняет плоские селекторы и минимальную специфичность в рамках разумного. Кажется, что здесь нет нужды в дополнительных инструментах (особенно учитывая богатый арсенал уже существующих решений).

tenbits commented 7 years ago

Не зависит от CSS Modules, но зависит от некоего кастомного преобразователя, который решает аналогичную задачу.

Разработка самой компоненты как раз не зависит от преобразователя, это обычный шаблон и привычные стили. Лишь во время сборки приложения стили выносятся в уникальные селекторы. Css Modules решает аналогичную проблему, но половинчатым путём. Они лишь генерируют уникальные селекторы, и дают нам json с полями. А мы уже в шаблонах через интерполяцию вставляем и комбинируем эти значения. А хотелось бы, что бы кто-то из существующего арсенала, взял шаблон компоненты, стили к нему, и преобразовал всё за меня, что бы эти стили не конфликтовали со стилями других компонент. Что-то знаете из существующих решений? То, как реализовали Scoped CSS у Angular или Veu отличный пример. Но мне кажется, что эта идея не до конца развита, и если в преобразователь "добавить" щепотку бэм-а, то будет очень даже хорошо)

Например, мне не нравиться, что они добавляют эти уникальные атрибуты к каждому html элементу. A имея такой селектор: header .title {}, они генерируют такое в стилях: header[_ngcontent-bge-1] .title[_ngcontent-bge-1], а хотелось бы .myComponent__header_title. Конечно же, их изначальная задача это симуляция scoped styles, но всё же.

То ли нет коллизий и есть проблема с поиском...

Именно что нет коллизий в стилях, а вот согласен, что проблемы с поиском могут быть. Но признаюсь, что у нас очень редко когда в компонентах по селекторам ищутся дом элементы (в основном всё завязано на bindings). Ну и в конце концов, идея лишь в какой-то степени добавить "полу-автоматический" бэм, а не заменить его.

tadatuta commented 7 years ago

Что-то знаете из существующих решений?

Мы описываем интерфейсы в BEMJSON, разметка генерируется с помощью шаблонов. Например:

{
    block: 'my-component',
    content: {
        elem: 'elem1',
        content: 'hello'
    }
}

Шаблонизатор умеет из такого описания сгенерировать

<div class="my-component">
    <div class="elem1">hello</div>
</div>

Попробовать можно здесь: http://bem.github.io/bem-xjst/

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

Далее. Стили мы описываем с использованием плагина для PostCSS rebem-css:

:block(my-component):elem(elem1) {

}

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

Остается JS, который мы пишем с помощью i-bem.js. Декларация компонентов выглядит так:

modules.define('my-component', ['i-bem-dom'], function(provide, bemDom) {
    provide(bemDom.declBlock(this.name, {}));
});

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

qfox commented 7 years ago

@tenbits А вам хочется побольше БЭМа в Ангуляр, или просто интересует, почему их подход менее гибкий?

tenbits commented 7 years ago

Владимир (@tadatuta) спасибо за приведённые примеры. Согласен, БЭМ инструментарий отличная вещь, но это уже куда больше, чем просто стилизация дом элементов. В данном рассуждении я пытаюсь подойти больше с точи зрения "прогрессивного усложнения", где вначале "И был у нас простой шаблон и стили". БЭМ методология здесь отлично ложится - на эту простоту. Особенно хорошо, если у нас один большой html, с множеством блоков. Но у нас много маленьких компонент, и иногда бэм просто кажется избыточным. Иногда проще, если мы знаем что это атомарный блок, написать что-то подобное:

<import bem scoped href='foo.less' rel='stylesheet' />
<div class='foo'>
    <h2>Foo</h2>
    <ul> 
        <li class='item'> Hello
    </ul>
</div>
.foo {  
    h2 {}
    .item {}
}

Пример конечно высосан из пальца, да и импортируем мы по другому, но для примера это не столь важно. Так вот, такое стилизовать можно хоть в codepen-e. Ну а после сборки шаблон и стили компонента будут выглядеть как-то так.

<div class='foo_ABC'>
    <h2 class='foo_ABC__h2'>Foo</h2>
    <ul> 
        <li class='foo_ABC__item'> Hello
    </ul>
</div>
.foo_ABC {}
.foo_ABC__h2 {}
.foo_ABC__item {}

И ещё раз, не обязательно вдаваться в такие крайности, можно и дальше придерживаться БЭМ методологии, но скажем с какими-то поправками, зная что у нас шаблоны разбиты на компоненты и что, в конце концов, когда собираются все view, никаких конфликтов имен не будет. Поэтому вот решил поинтересоваться, или кто-то думал уже о таких "поправках" и о таком подходе?

tenbits commented 7 years ago

Алексей (@zxqfox) , нет, это мы для своих нужд решили внедрить некий модульных подход для стилизации элементов. Иногда становиться сложно придумывать уникальные имена блоков(. И вот присматриваемся, кто как к этому подходит. Пока что, почти реализовали выше изложенный подход. Потихоньку будем внедрять и тестировать, посмотрим как оно придется нам по душе.