Инкапсуляция css стилей и компонентный подход

a50
4 min readFeb 3, 2018

--

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

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

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

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

Важную роль во всем этом играет еще то, как организована структура проекта. Чаще всего можно встретить свалку файлов в каталоге css(и не только там). Тому, кто пришел в проект бывает совсем не очевидно, в каком файле лежит нужный стиль и как стили одного файла влияют на стили другого файла.

Возможно, уже в ближайшем будущем, во всех браузерах будет реализована технология под названием Web Components, которая позволит инкапсулировать стили внутри компонента, но не смотря на то, что пока браузеры не всё умеют, много чего уже реализовано в компонентом стиле с помощью разных библиотек и полифилов, и это отлично работает, причем давно! Но бывают задачи, в которых использование мощных фреймворков и библиотек по разным причинам может быть не оправдано, не нужно или не возможно. Например, к таким задачам можно отнести создание статических шаблонов или создание встраиваемых элементов на существующий сайт.

Как это реализовано в популярных фреймворках?

Существует отличное решение под названием CSS Modules. Чаще всего это решение можно встретить в проектах, которые написаны с помощью библиотеки reactjs. Работает это следующим образом: внутри каждого JSX компонента подключается файл со стилями, например вот так:

import styles from ‘./mycomponent.css’

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

Очень здорово подошли к вопросу инкапсуляции стилей разработчики Angular. Каждый компонент изолирован, стили внутри компонента никогда не пересекутся со стилями другого компонента, даже если они будут иметь одинаковое имя класса. Это достигается путем добавления уникального рандомного атрибута к каждому тегу элемента. Этот же атрибут добавляется к каждому классу в css. Чтобы не пугать тех, кто не знаком с Angular, добавлю, что исходный код компонента html и css является “чистым”, уникальные атрибуты добавляются при сборке приложения. Все файлы лежат отдельно друг от друга.

Аналогичный подход применяется и в vue.js, называется он Scoped CSS

Для того чтобы в своих проектах можно было использовать такой подход не используя фреймворки и библиотеки, я решил написать плагин для gulp, который делает, примерно тоже самое, что Angular со стилями и html разметкой. Таким образом мы сможем реализовать инкапсуляцию стилей внутри компонента, при этом, нам ничего не помешает использовать глобальные стили, так как атрибут будет присвоен, только тем стилям и тегам, которые относятся к компоненту.

Чтобы в проекте был порядок, необходимо разбить каждый элемент макета на отдельные компоненты из которых потом будут собираться страницы. Думаю, что всем понятно, в чем сила компонентов. Если нет, то тут learn.javascript.ru/webcomponents-intro коротко и ясно объясняется.

Структура проекта

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

В каждом компоненте должен лежать файл html и css, если есть какая-то логика, то, там же следует разместить js файл.

Каждый компонент должен иметь свой тег. Желательно, чтобы в теге был дефис, например:

<my-component></my-component>

Такие правила заложены в стандарте custom elements, который пока мало где работает, но это не беда, рано или поздно заработает везде.

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

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

Вот такая получилась структура проекта:

После отработки всех gulp тасков, можно будет увидеть во что превратился код.

Скачать плагин и пример можно отсюда: код примера, плагин.

--

--