Недавно прочитал статью на Frontender Magazine «организация кода для CSS препроцессоров», в которой рассказывается о нескольких вариантах организации файловой структуры стилей в проекте, и решил поделиться своими размышлениями на эту тему. Я полагаю, что вы уже прочитали эту небольшую статью.

Окей, начнём, пожалуй с того, что я выскажу своё «фи» относительно представленных в статье архитектурах. Структуру, носящую название «функциональное разделение» сразу можно забросить, так как она представляет собой мусорку, в которой просто лежат файлы. Вариант «Катана» плох тем, что файл стилей контента будет бесконечным и не совсем ясно, как искать нужные стили. Шаблонное или страничное распределение плохо тем, что количество страниц может быть невелико, а их содержимое достигать предельных значений. Архитектура, предложенная Крисом Койером выглядит ужасно из-за того, что она олицетворяет мусорку из файлов. Коктейль «Хьюго» очень хорошо смотрится на фоне остальных решений, но страдает логикой распределения файлов по директориям. Почему страдает логикой? — вы скоро это узнаете. Относительно дополнения от Игоря Зенича я ничего сказать не могу, потому что не исповедую БЭМ-методологию.

Давайте более подробно пройдёмся по коктейлю «Хьюго». Мне непонятна логика разделения файлов препроцессора на директории. Ниже я сформировал несколько вопросов, на которые ответить себе я так и не смог:

  • Почему файл типографики (_typography.scss) находится в директории base, а файл стилей кнопок (_buttons.scss) — в директории components, ведь кнопки — это базовый элемент любой страницы.
  • Почему файл глобальных констант (_variables.scss) находится в директории помощников? — автор предполагает, что переменные, объявленные в этом файле являются вспомогательными, а не глобальными?
  • Почему примеси собраны в одном файле (_mixins.scss), а не вынесены в отдельную директорию? Ведь на большом проекте примеси могут исчисляться десятками и иметь солидные размеры, например, если это генератор сетки.

Как бы я улучшил коктейль «Хьюго»? — придумал свой коктейль, добавив больше логики и уделил должное внимание разбиению файлов препроцессора на директории. Итак, встречайте мои размышления на тему идеальной файловой структуры организации стилей проекта.

Просто взгляните на представленную ниже структуру и попробуйте ответить на вопрос — «куда я должен поместить файл стилей иконок?».

  • components/
    • _navbar.less
  • mixins/
    • _buttons.less
    • _clearfix.less
  • modules/
    • _buttons.less
    • _forms.less
    • _grid.less
    • _lists.less
    • _normalize.less
    • _scaffolding.less
    • _tables.less
    • _typography.less
  • pages/
    • _home.less
  • partials/
    • _footer.less
    • _header.less
    • _main.less
  • _variables.less
  • styles.less

Если вы ответили, что файл стилей иконок нужно поместить в директорию modules, то вы уже поняли суть моей структуры. Если же нет, то будем разбираться вместе.

Но перед тем как перейти к подробному разбору структуры, я хочу сказать, что в зависимости от задач здесь могут добавляться дополнительные директории, например, такие как library, helpers, themes. Директория library появляется в том случае, если проект использует библиотеки, которые невозможно найти в bower или npm. Директория helpers добавляется, если проект требует использования помощников (выравнивание текста, отступы и т.д.). И, наконец, директорию themes следует создавать в том случае, если в проекте предусмотрены дополнительные темы.

Теперь обратимся к файлу styles.less, который является точкой входа для всех стилей. Именно на него настраивается компилятор, и именно он соединяет все файлы препроцессора воедино.

К слову, я использую плагин less-plugin-glob для препроцессора Less, который позволяет импортировать файлы на основе glob-паттерна.

// Settings
@bowerDir: "bower_components";
@npmDir: "node_modules";

// Core
@import "_variables";

// Mixins
@import "mixins/**";

// Library
@import "modules/_normalize";

// Package managers
@import "@{bowerDir}/xy-flexbox/xy";

// Modules
@import "modules/!(_normalize)**";
@import "components/**";
@import "partials/**";
@import "pages/**";

Довольно легко догадаться, что файл _variables.less содержит глобальные константы. Под ними следует понимать переменные, необходимые всем модулям, компонентам или даже примесям. Однако, в этом файле не должно быть переменных, необходимых только одному компоненту или только одной теме — такие переменные описываются непосредственно в файле компонента или темы.

Mixins, partials и pages

Директория mixins содержит все примеси, используемые в проекте. В идеализированном случае, одна примесь — один файл, но никто не запрещает, допустим, написать две примеси для кнопок в одном файле.

Директория partials обычно включает в себя три файла стилей, которые стилизуют шапку (header), подвал (footer) и то, что между ними — центральную часть (main) сайта. Если вам необходимо поменять цвет фона шапки, то соответствующее свойство следует написать именно в файл _header.less, а не для каждого компонента, который используется в шапке. Точно такая же история и с подвалом, и с центральной частью.

В директорию pages складываются все файлы специфичных стилей для конкретных страниц. Так уж заведено, что каждая страница имеет уникальный для неё класс, присвоенный тегу body. Например, главная страница сайта имеет у тега body класс page-home, а страницы документации и полной версии записи (поста) имеет классы, соответственно, page-docs и page-post. Постараюсь ответить на вопрос: «что должно находиться в этих файлах?». Ответ довольно прост — специфичные для этой страницы стили, например, для изменения отображения какого-либо компонента.

Modules и components

Вот мы и подошли к самому важному — модулям и компонентам.

Модуль — это кирпичик, из которого строятся страницы или компоненты. Модуль включает в себя основные стили для элемента, который он пытается стилизовать. Например, файл _buttons.less стилизует кнопки и предоставляет различные вариации их отображения: цветные кнопки, групповые кнопки, кнопка как ссылка. Ещё одним примером может служить файл _tables.less, который стилизует таблицы и предоставляет, допустим, следующие их вариации: таблица с рамкой, таблица с «зеброй» и т.д.

Примеры модулей:

  • Кнопки
  • Элементы форм
  • Таблицы
  • Простые списки
  • Типографика
  • Сетка
  • Какие-то общие стили проекта (_scaffolding.less)

Теперь я отвечу на вопрос: «почему файл normalize находится в директории модулей?». Ответ довольно прост: потому, что ради одного файла нет смысла создавать целую директорию library, учитывая то, что этот файл может быть отредактирован (например, убраны стили по умолчанию для таблиц).

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

Такая идея используется в методологии RSCSS и БЭМ-методологии с той лишь разницей, что в их понимании блок — это форма, логотип, список ссылок и, наконец, глобальное меню, а здесь компонент — это нечто цельное, то есть лишь глобальное меню.

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

Примеры компонентов:

  • Глобальная навигация
  • Dropdown-меню
  • Рекламные блоки
  • Подсветка кода
  • Список статей
  • Jumbotron
  • Блок социальных кнопок
  • Список категорий или тегов
  • Стилизация контента статьи

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

Так что же с ответом на вопрос: «куда я должен поместить файл стилей иконок?». Теперь вы уже точно можете сказать, что файл стилей иконок следует поместить в директорию модулей, потому что иконка сама по себе может называться элементом, который включается и в контексте компонента, и без него.

Выводы

В статье на Frontender Magazine в конце каждого варианта организации стилей проекта приводится список плюсов и минусов, я полагаю, что стоит постараться объективно оценить и предложенный мной вариант:

Плюсы

  • Здесь присутствует логика и смысл
  • Строгое разбиение по предназначению
  • Легко поддерживать вручную
  • Каждый файл обещает быть небольшим по объему
  • Вы всегда знаете, что класс типа .navbar можно найти в директории components/_navbar.less

Минусы

  • Много директорий и файлов
  • Нужно думать: что есть модуль, а что есть компонент?
  • Иногда понятие компонента может быть расплывчатым