Стайл гайд для самых маленьких

Опубликовано 8/18/2015

В этом году у меня было несколько презентаций про SC5 Style Guide, в которых я делилась опытом использования инструмента на проектах одного их наших клиентов — мобильного оператора Elisa. Учитывая, что Elisa — огромная компания с массой вебсайтов, на которых нужно поддерживать единый стиль, не удивительно, что SC5 Style Guide как инструмент там очень полезен. Но как насчет небольших проектов? Стоит ли для них делать стайл гайды? Я сама не знала ответ на этот вопрос и захотела поэкспериментировать. В качестве подопытного сайта взяла собственный блог.

Живой стайл гайд моего блога выглядит вот так: varya.me/styleguide. Вы можете видеть весь интерфейс, разделенный на блоки, каждый из которых подразумевает самостоятельный компонент. Я до сих пор не смотрела на интерфейс своего блога в таком ключе, и это заставляет меня даже пересмотреть CSS-архитектуру проекта. Но давайте обо всём по порядку.

Настройка SC5 Style Guide

Всё начинается с установки пакета

npm install --save-dev sc5-styleguide

После этого я смогла сгенерировать веб-сайт стайл гайда. Для этого понадобилась парочка gulp тасков.

Мне нужно было немного отступить от конфигурации, которая предлагается в документации, чтобы решить свои задачи. Напишу об этом подробно.

Использование параметра appRoot

Мой стайл гайд находится не в корне домена, а в папке, которая называется styleguide. Об этом нужно сообщить инструменту, чтобы сгенерированное им приложение использовало верные ссылки:

gulp.task("styleguide:generate", function() {

  return gulp.src(["desktop.blocks/**/*.css"])
    .pipe(styleguide.generate({
      title: "Varya.me Styleguide",
      appRoot: '/styleguide',
      ...

Подключение JavaScript

В качестве значения параметра extraHead можно перечислить все, что нужно подключить к странице. У меня для некоторых компонент требуется JavaScript. Конечно, не обязательно делать так, чтобы он работал, можно просто делать стайл гайд только на базе CSS. Но мне хотелось, чтобы компоненты в документации выглядели бы абсолютно так же как в блоге. И благодаря extraHead я могу указать, какой JavaScript файл нужен.

gulp.task("styleguide:generate", function() {

  return gulp.src(["desktop.blocks/**/*.css"])
    .pipe(styleguide.generate({
      title: "Varya.me Styleguide",
      ...
      extraHead: [
        '<script src="http://yandex.st/jquery/1.7.2/jquery.min.js"></script>',
        '<script src="/desktop.bundles/index/index.min.js"></script>',
        ...
      ]
    ...

Но на самом деле нужна ещё одна хитрость. Мои компоненты написаны на i-bem.js и автоматически инициализируются по domReady. Это как раз то что нужно для блога, ведь страницы статические и вся HTML-разметка сразу загружается. Но сайт стайл гайда — это SPA (одностраничное приложение), и там это не работало. Компоненты отрисовываются на страницах стайлгайда "на лету", и очевидно, что это происходит позже domReady. То есть они не инициализируются автоматически. К счастью, можно использовать событие styleguide:onRendered на объекте window, которое SC5 Style Guide создаёт каждый раз, когда компонент перересовывается. Я сделала инициализацию компонент на это событие, то есть сразу после того как они появляются на странице. Такая инициализация нужна только на сайте стайл гайда, поэтому этот код не включается в общую сборку и подключается к стайл гайду как дополнительный файл.

gulp.task("styleguide:generate", function() {

  return gulp.src(["desktop.blocks/**/*.css"])
    .pipe(styleguide.generate({
      title: "Varya.me Styleguide",
      ...
      extraHead: [
        ...
        '<script src="/styleguide/i-bem__init_styleguide.js"></script>'
      ]
    ...

Вы можете посмотреть, как работают компоненты с JavaScript на примере блока, который показывает список репозиториев на GitHub после того как сделает запрос в GitHub API: varya.me/styleguide/#/section/4.3. Или на странице блока с кружочками, которые генерируются случайным образом: varya.me/styleguide/#/section/5.1.

И последняя, очень важная деталь для того, чтобы заставить JavaScript работать — это использование параметра disableEncapsulation: true. По умолчанию Style Guide оборачивает каждый компонент в ShadowDOM. Это даёт разработчику возможность не беспокоиться о том, что его стили пересекутся со стилями сгенерированного веб-сайта. Но в то же время это инкапсулирует компонент, в том числе и от JavaScript, подключённого в <head>. Но благодаря специальному параметру эту инкапсуляцию можно предотвратить. Так что у меня компоненты просто вставляются в HTML-код сайта как есть. Что касается возможности перезаписать стили сайта, этого не случится. Я использую БЭМ, поэтому все компоненты уже "инкапсулированы" на уровне методологии.

Стайл гайд как статическая страница

Для режима разработки у SC5 Style Guide запускается сервер, который разруливает все пути в корневой каталог, откуда и раздаётся сгененированный SPA-сайт. Если вы хотите пользоваться результатом в своём сервере, о такой маршрутизации придется позаботиться самостоятельно. Но в моём случае сайт располагается на GitHub Pages, это статический хостинг и там никакой маршрутизации не предусмотрено. Однако на этот случай есть настройка disableHtml5Mode: true. Она говорит генератору, что в приложении должны быть старые добрые ссылки с решеткой #. Так что всё работает.

Документирование компонент

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

Структурирование кода

Оказалось, что файловая структура, которую предлагает БЭМ, не самое лучшее решение для разработки живого стайлгайда. На файловой системе все компоненты представлены длинным плоским списком:

desktop.blocks/
├── article
├── articles-list
├── box
├── ...
└── text

github/varya/varya.github.com/desktop-blocks

То есть маленькие атомарные компоненты никак не отличаются от блоков для структуры страницы (таких как Header или Footer), от блоков из сайдбара или от CSS для сторонних виджетов. Разумеется, плоская структура более удобна для сборщиков, но с точки зрения разработки нужна какая-то каталогизация.

Для этого я сделала файл overview.css, в котором нет никакого активного CSS, но он помогает мне организовать блоки. У меня там 5 секций, и в каждой относящиеся к ней компоненты:

/*
Atoms

Styleguide 1

styleguide:ignore:start

@import url("logo/logo.css"); // 1.1
@import url("text/text.css"); // 1.2
...

styleguide:ignore:end
*/

/*
Main blocks

Styleguide 2

styleguide:ignore:start

@import url("header/header.css"); // 2.1
...

styleguide:ignore:end
*/

github/varya/varya.github.com/desktop-blocks/overview.css

По сути в файле кроме комментариев ничего нет. А в комментариях — описание каждой секции. Также перечислены файлы блоков, имеющие к ней отношение. Это удобно для навигации по коду. В этом перечислении я использовала @import (просто потому что могу).

Здесь только одна особенность — использование волшебных комментариев styleguide:ignore:start и styleguide:ignore:end. Ими можно обернуть любой кусок CSS (SASS или LESS) кода и таким образом сказать генератору SC5 Style Guide, что этот кусок нужно проигнорировать.

Я игнорирую свои списки блоков, потому что они никак не влияют на код. Но описания секций остаются.

Описание блоков

Все остальное легко. Перед каждым компонентом я размещаю комментарий с KSS описанием. Например, один из простых блоков, Logo:

/*

Logo

markup:
<logo class="logo">···<b class="var">var</b>·<b class="ya">ya</b>;<b class="cursor"></b></logo>

Styleguide 1.1

*/
.logo
{
...

github/varya/varya.github.com/desktop-blocks/logo/logo.css

See it rendered: varya.me/styleguide/#/section/1.1

В некоторых компонентах использованы дополнительные возможности. Например, социальные иконки — это один и тот же блок с разными модификаторыми. Такое можно задокументировать одним махом:

/*
Social icon

.social-ico__ico_type_rss         - RSS
.social-ico__ico_type_twitter     - Twitter
.social-ico__ico_type_github      - Github
.social-ico__ico_type_facebook    - Facebook
.social-ico__ico_type_linkedin    - LinkedIn

markup:
<a class="link social-ico__ico {$modifiers}" href="#" title="Icon title"></a>

Styleguide 1.5.1
*/

.social-ico__ico
{
...

github/varya/varya.github.com/desktop-blocks/social-ico/social-ico.css

В документации компоненты прорисованны по отдельности для каждого модификатора: varya.me/styleguide/#/section/1.5.1

Для сложносоставных компоненты, которые используют внутри себя другие, я использовала ключевой тег <sg-insert>. Он вставляет вместо себя код компонента с соответствующим номером.

/*
Sidebar
markup:
<nav class="sidebar">
  <sg-insert>4.2</sg-insert>
  <sg-insert>4.3</sg-insert>
</nav>
Styleguide 4.1
*/

.sidebar
{
...

github/varya/varya.github.com/desktop-blocks/sidebar/sidebar.css

Благодаря этому документация в коде приемлемого размера, а на сайте все раскрывается в полном виде: varya.me/styleguide/#/section/4.1

Style-Guide-Driven Development

Если в получившемся стайл гайде в поле для поиска вы наберете "logo", то увидите все компоненты, который используют логотип! Поиск проводится по всему коду. Точно так же можно поискать компоненты, в разметке которых используется <em>. Или в чьих стилях есть font:.

Мне лично особенно нравится, что можно искать и по разметке. Этим можно пользоваться во время рефакторинга. Например, изменив input, я могу найти все использующие его блоки и посмотреть, не сломались ли они.

Хотя на самом деле это лишь небольшое дополнение к главному преимуществу использования стайл гайда. По-моему, его основной плюс — демонстрация ошибок вёрстки.

В CSS моего блога ещё до внедрения стайл гайда использовался компонентый подход. Учитывая мой БЭМ опыт, я была на 100% уверена, что компоненты написаны хорошо. Но даже такая компонентная разработка всё равно происходила с точки зрения страницы. До того как блоки были внедрены в блог, я делала их на отдельной статической странице. То есть отдельно, вне страницы, они никогда и не существовали.

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

После того как SC5 Style Guide волшебным образом отрисовал их по отдельности, я могу видеть, что блок logo выровнен по правому краю. Хотя почему бы это? Очевидно, это моя ошибка, допущенная, когда я верстала логитип внутри блока Header.

То же самое произошло с переключалкой языков, она так же выровнена вправо.

В блоке социальных иконок переключалка языков подразумевалась рядом с иконкой RSS. Но на странице они располагаются близко друг к другу только потому что весь блок помещен в узкий контейнер. В стайл гайде блок отрисован отдельно, и мне теперь видно, что он свёрстан неидеально.

Конечно, такие открытия подразумевают скорый рефакторинг :-)

И в довершение нужно сказать, что эксперимент не закончен. Есть и другие открытия для новых постов.