Методология и архитектура CSS
В течение многих лет я использовал ITCSS в качестве архитектуры Goto CSS для больших проектов. Это помогло мне сохранить мой CSS поддерживаемым с небольшой командой. Но в последние два года я стал больше применять утилиты и меньше писать компоненты / блоки CSS. Все больше и больше частей ITCSS оставались нетронутыми и неиспользованными. Моя архитектура CSS стала слишком сложной для повседневного использования. И это был не только я. Вы видите движение в сообществе, но также и в моей собственной команде.
Я не любитель утилит. Но в наши дни 80% моего кода CSS - это утилиты. Остальные части состоят из макетов таргетинга CSS (например, сеток) и блоков, которые могут быть решены с помощью утилит (например, с использованием таких операторов, как +
или ~
). На данный момент, я наткнулся на CUBE CSS с Энди Беллом. Это методология, описывающая, как я внедрял и до сих пор использую CSS. Итак, как каждый уважающий себя front-end разработчик, присутствующий в сети, я взял его, изменил, создал фреймворк и написал об этом!
От методологии к фреймворку
CUBE CSS - это методология, в основе которой лежит простота. Он ценит CSS таким, какой он есть. Методология хорошо работает с настраиваемыми свойствами для реализации фреймворка. Комбинация создает гибкую, масштабируемую и расширяемую архитектуру CSS. Пользовательские свойства действуют как маркеры дизайна и могут использоваться на всех уровнях архитектуры. Моя структура состоит из трех слоев.
- Макет: классы, которые смотрят на макроуровень приложения. Они предоставляют гибкие решения макета, общие для всего приложения.
- Утилиты: классы, которые выполняют одно задание и выполняют его хорошо. Часто это класс, изменяющий одно свойство. Но такие утилиты, как
.click-area
, охватывают более одного свойства, но при этом делают только одно. - Блоки: соответствуют компонентам пользовательского интерфейса. То, что не может быть решено только с помощью классов компоновки и / или служебных программ, может быть решено блоками. Вы можете выбрать охват всех стилей компонента в блоке или поместить в блок только те стили, которые не охвачены другими классами.
CUBE CSS включает четвертый слой, исключения. Хотя мне нравятся атрибуты тегов HTML data-
, я считаю их частью блоков.
Если вы внимательно посмотрите на код моего фреймворка (Feo), он имеет архитектуру, описанную ниже. Как видите, он фокусируется только на макетных и служебных классах. Блоки и исключения очень специфичны для проекта и часто связаны с компонентами пользовательского интерфейса. Поэтому они не рассматриваются в данной структуре. Однако есть много способов добавления блоков в проект в сочетании с этой структурой. Вы можете добавить каталог в структуру, но я бы посоветовал разместить его рядом с соответствующими компонентами пользовательского интерфейса. Вы можете сделать это с помощью модулей CSS, компонентов стилей, стилей с областью видимости в Svelte и т. д.
styles/
├── layout/ // classes for layout patterns
├── utilities/ // utility classes
├── _global.scss // global styles targeting HTML tags
├── _reset.scss // CSS reset
├── _tokens.scss // design tokens
└── index.scss
Для правильной реализации и использования требуются некоторые базовые знания о специфике и каскаде. Многие шаблоны макета будут применять свойства CSS с большей специфичностью по сравнению с утилитами. В некоторых случаях специфичность может быть такой же, но вам не следует переопределять свойства макета с помощью утилит.
Детальный взгляд на фреймворк
В его основе лежит файл _token.scss
. В этом файле вы определяете все свои проектные токены как переменные SCSS. Но почему бы не определить их как настраиваемые свойства? Поскольку фреймворк является расширяемым, вы должны иметь возможность определять свои собственные имена для переменных с вашими предпочтительными именами. Вы хотите использовать -xs
или -4
в качестве имени для интервала? Это делает невозможным правильное определение всех служебных классов. Но, используя переменные SCSS в качестве определений, мы можем генерировать настраиваемые свойства, которые можно использовать для всех ваших дополнительных (блочных) классов.
$colors: (
'black': #000,
'white': #fff
);
:root {
@each $name, $color in $colors {
--#{$name}: #{$color};
}
}
С помощью токенов дизайна мы можем сгенерировать все служебные классы. Вместо того, чтобы устанавливать значения всех служебных классов, мы обращаемся к соответствующему настраиваемому свойству, как показано ниже. Предположим, вы изменили значение --black
для конкретной страницы на #fff
. Все служебные классы (и блоки), которые имеют ссылку на настраиваемое свойство --black
, теперь будут использовать значение #fff
, а не #000
на этой конкретной странице. Это создает согласованный, но гибкий опыт как для пользователя, так и для разработчика. Мы позволяем каскаду CSS делать свою работу для настраиваемых свойств.
@each $name, $color in $colors {
.bg-#{$name} {
background-color: var(--#{$name});
}
}
Аналогичный подход используется для шаблонов макета. Многие из шаблонов макета все еще имеют свойства, которые вы хотите настроить. Возьмем пример ниже. Это создает отзывчивый обзор плиток. Но вы хотите иметь возможность установить размер зазора. Создавая служебные классы, мы позволяем разработчикам устанавливать классы, как tiles tiles-g-xs
на элементах. Аналогичным образом могут быть идентифицированы другие свойства, которые могут быть заменены дополнительными служебными классами компоновки (например, заменой 20rem
). Хотя при этом стираются границы между компоновкой и утилитами, это нормально. Это помогает достичь цели охвата 80% применяемых стилей этой структурой.
.tiles {
--tiles-gap: var(--spacing-0);
display: grid;
grid-row-gap: var(--tiles-gap);
grid-column-gap: var(--tiles-gap);
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
width: 100%;
}
// Generate classes to set the tile gap
@each $name, $space in $spacing {
.tiles-g-#{$name} {
--tiles-gap: var(--spacing-#{$name});
}
}
Подведение итогов
В тот момент, когда я прочитал о CUBE CSS, я был поклонником этой методологии. По сути, он описывал, как я отношусь к CSS и как я его использую. В то же время я стал большим поклонником свойств клиентов. Так почему бы не объединить их в одну структуру? Что я и сделал. Текущая версия фреймворка открыта на GitHub. Он небольшой, но используется в двух проектах. В него встроено несколько классов компоновки и утилит. На данный момент я намерен продолжать улучшать и обогащать структуру, когда смогу. Сообщите мне в выпусках GitHub, что, по вашему мнению, следует добавить!