Изоляция CSS-стилей

Интересное видео опубликовал Вадим Макеев «Прототип изоляции стилей для Shower на веб-компонентах», где затрагивается вопрос изоляции css-стилей при верстке. Само видео посвящено одной из попыток реализации, но сама по себе тема (изоляции) мне кажется интересна, поскольку с ней сталкиваются практически каждый верстальщик.

В чём суть проблемы? CSS-стили имеют глобальную обрасть видимости. Не важно где объявлен стиль, он будет применён сразу ко всей html-странице. Пока html-код небольшой, особых проблем не возникает, поскольку элементарно решается за счёт именования css-классов. Но, как только html становится побольше, то именование классов должно быть более осмысленным, иначе разобраться в коде будет проблематично.

Но это ещё не всё. Существуют блоки, которые довольно сложны по своей html-структуре. Например шапка сайта может содержать в себе flex-сетку со множеством вложенных функциональных блоков (меню, логотипы, ссылки, иконки и т.д.). Скорее всего такой блок будет оформлен в виде отдельного html/php-файла, который просто подключается на странице. Но, если html-разметку мы можем разделить по файлам и верстать индивидуально, то с css-стилями такой «финт не прокатит», поскольку, опять же css имеет глобальную область видимости.

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

Web-компоненты по сути представляют собой не просто блоки, а некие элементы, которые можно многократно встраивать на страницу. В качестве примера можно привести тэги VIDEO или AUDIO, которые на странице отображаются в виде сложных функциональных блоков (кнопки, полоса прогресса и т.п.).

Но веб-компоненты это отдалённое будущее, а проблема глобальной видимости CSS актульна сейчас, поэтому есть несколько базовых подходов/методик к её решению (точнее эмуляции). Я сразу отбрасываю использование JS, поскольку это совсем уж сложные варианты. Остановимся только на голом HTML и CSS, поэтому единственным способом будет — это использование атрибута class (или id, но это не совсем «кошерно»).

На уровне HTML

Самое главное — это указать контейнер для блока. Всё, что оказывается внутри — и есть компонент (включая сам контейнер). В идеале такой блок можно было бы разместить в любой части страницы простым копированием.

<div class="block1">
    <h1>Первый блок</h1>
    <div>Текст</div>
</div>
 
<div class="block2">
    <h1>Второй блок</h1>
    <div>Текст</div>
</div>

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

CSS каскадность

Если применить

h1 { color: red; }

то оба заголовка станут красными. На выручку приходит каскадность:

.block1 h1 { color: red; }
.block2 h1 { color: green; }

Очевидно, что данный подход наиболее простой и эффективный. При использовании препроцессора Sass получится вполне себе элегантный и красивый код:

.block1 { 
    h1 { color: red; }
    // прочие блоки
    div { }
}
 
.block2 { 
    h1 { color: green; }
 
    // прочие блоки
    div { }
}

Уникальность именования классов

Данный подход используется в методологии БЭМ, где каждый элемент обязательно содержит класс и именуется от своего родителя.

<div class="block1">
    <h1 class="block1_h1">Первый блок</h1>
    <div class="block1_div">Текст</div>
</div>
 
<div class="block2">
    <h1 class="block2_h1">Второй блок</h1>
    <div class="block2_div">Текст</div>
</div>

В css-стилях, при этом, происходит отказ от каскадности:

.block1_h1 { color: red; }
.block1_div { }
 
.block2_h1 { color: green; }
.block2_div { }

В Sass это может выглядеть так:

.block1 { 
    &_h1 { color: red; }
    // прочие блоки
    &_div { }
}
 
.block2 { 
    &_h1 { color: green; }
 
    // прочие блоки
    &_div { }
}

Здесь мы видим уже усложнение кода, но самое главное — это отказ от фундаментальной основы CSS — каскадности. То есть код усложнился, добавились запутанные правила именования, но при этом он не дал никакого выигрыша. Когда вложенных элементов окажется много, БЭМ классы превращаются в жуткое мессиво. При том, я отмечу, только за счёт идиотского отказа от каскадности. Но, в любом случае, такой подход всё-таки тоже решает задачу изоляции css-стилей.

Утилитарные классы

Поскольку я сторонник атомарного CSS, то покажу как это решается с помощью утилитарных классов. Например в UniCSS есть классы для красного и зеленного цветов. В этом случае css-код вообще не правится, а сразу используются готовые классы:

<div>
    <h1 class="t-red">Первый блок</h1>
    <div>Текст</div>
</div>
 
<div>
    <h1 class="t-green">Второй блок</h1>
    <div>Текст</div>
</div>

Обратите внимание, что у родителя я убрал идентифицирующий класс. В Atomic CSS классы просто так у тэгов не прописываются. Если корневой DIV не имеет особых стилей, то нет нужды указывать и какие-нибудь классы. Это же относится и к любым другим тэгам.

Данный пример достаточно простой, но он показывает, что проблему верстки можно решить без изоляции стилей. Конечно атомарный CSS может и не содержать нужных классов, в этом случае придётся создать класс для контейнера и использовать описанный выше вариант с каскадностью. Если же это какой-то простой стиль, то можно вообще использовать style у тэга.

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

Оставьте комментарий!

Комментарий будет опубликован после проверки. Вы соглашаетесь с правилами сайта.

(обязательно)