javascript

Изоляция css стилей с помощью компонентного подхода

  • понедельник, 14 августа 2017 г. в 03:10:55
https://habrahabr.ru/post/335510/
  • Разработка веб-сайтов
  • JavaScript
  • HTML
  • CSS


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

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

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

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

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

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

Как делают другие?


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

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

Докатились до того, что, в js запихнули не только html, но стали писать еще и css, ломая устоявшиеся стереотипы, что так делать плохо. И тут можно сказать, что мы возвращаемся к тому с чего начали, свалка из структуры проекта перекочевала в код компонента.

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

Пару слов про новый велик


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

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

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


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

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

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

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

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

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


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



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



Код примера
Плагин