HUG CSS, как я подхожу к архитектуре CSS

Источник: «HUG CSS, how I approach CSS architecture»
Сегодня я хочу рассказать о том, как я подхожу к CSS-архитектуре в своих проектах. Давайте покопаемся!

Вчера я писал о бесклассовых и основанных на классах CSS дизайн-системах. В статье я отметил...

Между бесклассовой и основанной на классах дизайн-системами есть нечто среднее.

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

Не знаю, можно ли назвать их бесклассовыми+ или основанными на классах-лайт, но они находятся где-то посередине.

Сегодня я хочу рассказать о том, как я подхожу к CSS-архитектуре в своих проектах. Давайте покопаемся!

Подход

Я использую следующий подход для всех CSS-проектов, над которыми работаю...

  1. Бесклассовый HTML для основных стилей.
  2. Утилитарные классы для улучшения и подстройки элементов при необходимости.
  3. Групповые классы упрощающие стилизацию коллекций элементов, могут иметь более сложные требования.

Если кратко, то это HTML, Utility, Group, или HUG CSS.

Основные стили HTML

Я применяю стили по умолчанию непосредственно к HTML-элементам.

Вот упрощённый пример…

/* Списки */
ul,
ol
{
margin: 0 0 1.5em 2em;
padding: 0;
}

li {
margin-bottom: 0.5em;
}

/* Заголовки */
h1, h2, h3, h4, h5, h6 {
font-family: "Comic Sans", sans;
line-height: 1.4;
margin: 0 0 1em;
padding: 0;
word-wrap: break-word;
}

/* Кнопки */
button {
background-color: #0088cc;
border: 0.125em solid #0088cc;
border-radius: 0.25em;
color: #ffffff;
display: inline-block;
font-size: 0.9375em;
font-weight: normal;
line-height: 1.2;
margin-right: 0.3125em;
margin-bottom: 0.3125em;
padding: 0.5em 0.6875em;
}

button:hover,
button:active
{
background-color: #f7f7f7;
border-color: #808080;
color: #272727;
}

Это позволяет писать HTML, не прибегая к использованию классов для всего…

<h2>Awesome wizards</h2>

<ul>
<li>Merlin</li>
<li>Yennefer</li>
<li>Radagast</li>
</ul>

<button>Add a Wizard</button>

Утилитарные классы

Стили HTML по умолчанию в большинстве случаев работают отлично. Но часто дизайн требует отклонений от стандартного представления.

Мне очень нравятся утилитарные классы. Утилитарный класс — это класс, который обычно изменяет только одно или два свойства элемента.

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

Я могу написать утилитарный класс .no-margin-bottom, отменяющий свойство margin-bottom по умолчанию.

.no-margin-bottom {
margin-bottom: 0;
}
<h2 class="no-margin-bottom">Awesome Wizards</h2>
<p>Which one do you like best?</p>

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

/* Размеры текста */
.text-small {
font-size: 0.9375em;
}

.text-large {
font-size: 1.1875em;
line-height: 1.4;
}

/* Цвета текста */
.text-muted {
color: #808080;
}

Групповые классы

Иногда для коллекции элементов требуется более сложная стилизация.

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

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

<!-- Инлайн-список? -->
<ul class="list-style-none display-flex flex-gap flex-center flex-wrap">
<li>Merlin</li>
<li>Yennefer</li>
<li>Radagast</li>
</ul>

Многие называют это "Tailwind-стилем" создания CSS. Он работает и может быть полезен для быстрого создания прототипов, но в долгосрочной перспективе с ним очень неудобно работать.

Для подобных случаев у меня есть групповой класс .list-inline, который делает то же самое с помощью одного класса.

.list-inline {
list-style: none;
display: flex;
align-items: center;
column-gap: 1em;
flex-wrap: wrap;
}
<!-- Инлайн-список -->
<ul class="list-inline">
<li>Merlin</li>
<li>Yennefer</li>
<li>Radagast</li>
</ul>

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

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

Например, у меня есть несколько классов .list-inline-*, регулирующих величину интервала между элементами списка.

.list-inline-spaced {
column-gap: 2.875em;
}

.list-inline-compact {
column-gap: 0.5em;
}
<!-- Инлайн-список с увеличенным пространством между элементами -->
<ul class="list-inline list-inline-spaced">
<li>Merlin</li>
<li>Yennefer</li>
<li>Radagast</li>
</ul>

Утилитарные "классы" не всегда должны быть классами.

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

Например, кнопка с активным и неактивным состояниями должна иметь атрибут [aria-pressed] со значением true или false соответственно.

<button aria-pressed="true">Save to Favorites</button>

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

[aria-pressed="true"] {
background-color: #ff4136;
border-color: #ff4136;
color: #ffffff;
}

Это избавляет JavaScript от необходимости управлять атрибутом состояния и классом, снижая вероятность возникновения ожидаемых ошибок.

Краткий обзор

Подведём итоги…

  1. Бесклассовый HTML для основных стилей.
  2. Утилитарные классы для улучшения и подстройки элементов при необходимости.
  3. Групповые классы упрощающие стилизацию коллекций элементов, могут иметь более сложные требования.

Это HTML, Utility, Group, или HUG CSS.

Дополнительные материалы

Предыдущая Статья

Бесклассовые vs. основанные на классах дизайн-системы CSS

Следующая Статья

Оптимизация запросов MySQL