Заголовок статьи
Колонка не растягивается шире шестидесяти символов: на широком экране остаток ширины уходит в равные поля слева и справа, на узком — колонку держат боковые отступы.
Margin и padding с шагом 0.25rem по разреженной шкале от 0 до 4rem. По сторонам, по осям, авто-маржины и адаптивные варианты у каждого свойства.
Число в имени класса — это множитель базового шага 0.25rem.
gr-m-4 = 4 × 0.25rem = 1rem,
gr-p-16 = 16 × 0.25rem = 4rem.
Значения вне шкалы. Разовый отступ задаётся
произвольным значением — gr-mt-[13px]. Правило собирает
рантайм, поэтому без JS такой класс не работает: см.
Произвольные значения.
Ступеней двенадцать: 0 1 2 3 4 5 6 7 8 10 12 16. Мелкий шаг
сохранён там, где важна точность, — до 2rem; дальше идут секционные отступы
2.5rem, 3rem и 4rem.
| Класс | rem | px при базе 16px |
|---|---|---|
.gr-m-0 / .gr-p-0 | 0 | 0 |
.gr-m-1 / .gr-p-1 | 0.25rem | 4px |
.gr-m-2 / .gr-p-2 | 0.5rem | 8px |
.gr-m-3 / .gr-p-3 | 0.75rem | 12px |
.gr-m-4 / .gr-p-4 | 1rem | 16px |
.gr-m-5 / .gr-p-5 | 1.25rem | 20px |
.gr-m-6 / .gr-p-6 | 1.5rem | 24px |
.gr-m-7 / .gr-p-7 | 1.75rem | 28px |
.gr-m-8 / .gr-p-8 | 2rem | 32px |
.gr-m-10 / .gr-p-10 | 2.5rem | 40px |
.gr-m-12 / .gr-p-12 | 3rem | 48px |
.gr-m-16 / .gr-p-16 | 4rem | 64px |
Изменение в 0.7.0. Раньше шкала шла подряд от 0 до 16 —
17 ступеней, 1193 класса, две трети всей библиотеки. Ступени
9, 11, 13, 14 и
15 убраны: за ними не стоит ни одного реального сценария,
который не решался бы соседней ступенью. Нужное промежуточное значение
задаётся обычным CSS.
| Суффикс | CSS-свойство | Пример |
|---|---|---|
-t | top | .gr-mt-4 → margin-top: 1rem |
-b | bottom | .gr-mb-4 → margin-bottom: 1rem |
-s | начало строки | .gr-ms-4 → margin-inline-start: 1rem |
-e | конец строки | .gr-me-4 → margin-inline-end: 1rem |
-x | обе стороны строки | .gr-mx-4 → margin-inline: 1rem |
-y | top + bottom | .gr-my-4 → margin-top + margin-bottom: 1rem |
-s и -e — логические стороны строки: в LTR это
левый и правый край, в RTL они меняются местами сами. Физических
-l и -r в шкале больше нет — подробнее
в разделе «Направление письма».
Каждое свойство — по всем двенадцати ступеням шкалы:
.gr-m-{n} /* margin */
.gr-p-{n} /* padding */
.gr-mt-{n} /* margin-top */
.gr-mb-{n} /* margin-bottom */
.gr-pt-{n} /* padding-top */
.gr-pb-{n} /* padding-bottom */
.gr-ms-{n} /* margin-inline-start */
.gr-me-{n} /* margin-inline-end */
.gr-ps-{n} /* padding-inline-start */
.gr-pe-{n} /* padding-inline-end */
.gr-mx-{n} /* margin-inline */
.gr-my-{n} /* margin-top + margin-bottom */
.gr-px-{n} /* padding-inline */
.gr-py-{n} /* padding-top + padding-bottom */
/* где {n} — одно из: 0 1 2 3 4 5 6 7 8 10 12 16 */
padding со всех сторон
padding 1.5rem
padding 2rem
| Класс | CSS | Применение |
|---|---|---|
.gr-mx-auto | margin-inline: auto | Центрирование блока |
.gr-ms-auto | margin-inline-start: auto | Прижать к концу строки (во flex) |
.gr-me-auto | margin-inline-end: auto | Прижать к началу строки (во flex) |
Суффикс брейкпоинта в конце имени класса: .gr-p-8-md.
Правило применяется начиная с указанной ширины экрана. Адаптивные
варианты есть у всех свойств шкалы — физических, логических
и осевых — и у авто-маржинов .gr-mx-auto,
.gr-ms-auto, .gr-me-auto.
Логические -s и -e адаптивны
по всей шкале. .gr-ms-4-md и контейнерный
.gr-ms-4-cmd существуют наравне с .gr-mt-4-md:
односторонний отступ от брейкпоинта разворачивается в RTL так же,
как и базовый.
| Базовый класс | Адаптивный вариант | Применение |
|---|---|---|
.gr-m-4 | .gr-m-4-md | margin: 1rem от 768px |
.gr-p-8 | .gr-p-8-lg | padding: 2rem от 1024px |
.gr-mt-2 | .gr-mt-2-sm | margin-top: 0.5rem от 640px |
.gr-mb-6 | .gr-mb-6-xl | margin-bottom: 1.5rem от 1280px |
.gr-mx-auto | .gr-mx-auto-md | Центрирование от 768px |
.gr-py-4 | .gr-py-4-lg | padding по вертикали от 1024px |
<div class="gr-p-4 gr-p-8-md gr-p-12-lg">
Адаптивный padding: 1rem → 2rem → 3rem
</div>
Доступные суффиксы: -sm, -md, -lg, -xl.
Изменение в 0.7.0. Префиксная форма
.gr-md:p-8 удалена. Раньше спейсинг был единственным модулем
с двоеточием, а всё остальное — flex, grid, типографика, видимость —
использовало суффикс. Теперь синтаксис в библиотеке один:
.gr-md:p-8 → .gr-p-8-md.
Классы, работающие вдоль строки, — логические: они
называют сторону строки, start и end,
и разворачиваются сами, когда на элементе или предке стоит
dir="rtl". Правил на [dir] в библиотеке нет:
разворотом занимается браузер. Физические односторонние классы удалены —
замена по таблице соответствия ниже.
| Было (удалено) | Стало | Свойство |
|---|---|---|
.gr-ml-{n} / .gr-mr-{n} | .gr-ms-{n} / .gr-me-{n} | margin-inline-start / -end |
.gr-pl-{n} / .gr-pr-{n} | .gr-ps-{n} / .gr-pe-{n} | padding-inline-start / -end |
.gr-ml-auto / .gr-mr-auto | .gr-ms-auto / .gr-me-auto | margin-inline-start / -end: auto |
Суффиксы брейкпоинтов переносятся как есть: .gr-ml-4-md →
.gr-ms-4-md, .gr-pl-2-clg →
.gr-ps-2-clg. Эта же таблица — в журнале изменений.
Осевые .gr-mx-* и .gr-px-* записаны логическими
сокращениями margin-inline и padding-inline: обе
стороны получают одно значение, поэтому направление письма результата не
меняет, а объявлений выводится вдвое меньше.
Физические односторонние классы удалены. Это
единственное запланированное ломающее изменение библиотеки: класс
вида .gr-ml-4 нельзя было молча переопределить
в логический — разметка, выбравшая левую сторону буквально, сменила
бы смысл. Классы удалены целиком, замена — по таблице выше. Верх
и низ (.gr-mt-*, .gr-pb-*) остаются
физическими: блочная ось в RTL не разворачивается. Стороне, нужной
буквально из-за геометрии экрана, остаётся свой CSS.
Ходовые задачи вёрстки, в которых отступы работают вместе с соседями
по библиотеке: флексом и гридом ядра, токенами .gr-gap-*,
типографикой, цветами и компонентами ui. Классов «секция», «стек» или
«медиа-объект» в библиотеке нет намеренно: каждый такой блок — это два-три
отступа в правильных местах, и рецепты ниже показывают, в каких именно.
Страница-лендинг — стопка секций с одинаковым вертикальным ритмом:
.gr-py-8 .gr-py-12-md даёт 2rem на телефоне и 3rem
на десктопе — адаптивные варианты избавляют от медиазапросов в CSS.
Секции разделяются не бордерами, а чередованием фонов:
чётным — .gr-bg-surface, нечётные остаются на фоне страницы.
Шапка секции — три ступени отступов по убыванию связности: надзаголовку
.gr-mb-2, заголовку .gr-mb-3, а подводке —
крупный .gr-mb-8, отделяющий шапку от содержимого.
<section class="gr-py-8 gr-py-12-md gr-px-4 gr-bg-surface">
<p class="gr-text-xs gr-uppercase gr-font-semibold gr-text-primary gr-text-center gr-mb-2">Возможности</p>
<h2 class="gr-text-center gr-mb-3">Всё нужное уже внутри</h2>
<p class="gr-text-center gr-text-ink-secondary gr-mb-8">Подводка секции — один-два абзаца серым.</p>
<div class="gr-grid-1 gr-grid-3-md gr-gap">
<div class="gr-p-4">Карточка</div>
<div class="gr-p-4">Карточка</div>
<div class="gr-p-4">Карточка</div>
</div>
</section>
.gr-py-* + шапка на трёх ступенях .gr-mb-*Возможности
Подводка секции — один-два абзаца серым.
Статья или подводка не должны растягиваться на всю ширину экрана — строка
длиннее 60–75 символов тяжело читается. Пара «предел ширины + авто-поля»
решает это двумя классами: .gr-max-w-[60ch] задаёт предел
в символах текущего шрифта (произвольное значение — собирает
рантайм), а .gr-mx-auto
делит остаток ширины поровну между полями. Боковые
.gr-px-4 не дают колонке прилипнуть к краям экрана,
пока он ýже предела.
<article class="gr-max-w-[60ch] gr-mx-auto gr-px-4">
<h1>Заголовок статьи</h1>
<p>Текст читаемой ширины на любом экране…</p>
</article>
.gr-max-w-[60ch] + .gr-mx-autoКолонка не растягивается шире шестидесяти символов: на широком экране остаток ширины уходит в равные поля слева и справа, на узком — колонку держат боковые отступы.
Когда элементы однородны — поля формы, пункты списка, абзацы карточки, —
интервал лучше отдать контейнеру: .gr-flex .gr-flex-col .gr-gap
ставит одинаковый промежуток между всеми потомками, и у стопки нет ни
«двойных» отступов на стыках, ни лишнего поля после последнего элемента.
Мелкий ритм внутри группы «метка → поле → подсказка» уже держит
.gr-field из ui — отступы руками ему не нужны. Парные поля
встают в одну строку сеткой .gr-grid-2-sm с мелким зазором
.gr-gap-sm, а кнопки дожимает вправо
.gr-flex-end. Маржины при этом остаются для неоднородного
ритма — как три ступени в шапке секции из первого рецепта.
<form class="gr-flex gr-flex-col gr-gap">
<div class="gr-grid-1 gr-grid-2-sm gr-gap-sm">
<div class="gr-field">
<label class="gr-label" for="name">Имя</label>
<input class="gr-input" id="name" type="text">
</div>
<div class="gr-field">
<label class="gr-label" for="surname">Фамилия</label>
<input class="gr-input" id="surname" type="text">
</div>
</div>
<div class="gr-field">
<label class="gr-label" for="mail">Почта</label>
<input class="gr-input" id="mail" type="email">
<p class="gr-hint">Пришлём ссылку для подтверждения.</p>
</div>
<div class="gr-flex gr-flex-end gr-gap-sm">
<button class="gr-btn gr-btn-ghost" type="button">Отмена</button>
<button class="gr-btn gr-btn-primary" type="submit">Сохранить</button>
</div>
</form>
.gr-flex-col .gr-gap, внутри групп — .gr-field
Аватар с текстом, иконка с описанием фичи, пункт уведомления — везде одна
схема: .gr-flex .gr-gap-sm .gr-flex-items-start, слева
фигура фиксированного размера (здесь — .gr-avatar из ui),
справа текстовый блок. Текст получает .gr-min-w-0: без него
флекс-потомок не сжимается ýже своего содержимого, и длинное слово
распирает строку. Внутренний ритм текста — сброс .gr-m-0
плюс точечный .gr-mt-1, а стопку комментариев разделяет
всё тот же .gr-flex-col .gr-gap из предыдущего рецепта.
<div class="gr-flex gr-flex-col gr-gap">
<div class="gr-flex gr-gap-sm gr-flex-items-start">
<span class="gr-avatar">АК</span>
<div class="gr-min-w-0">
<p class="gr-m-0 gr-font-semibold">Анна Ковалёва</p>
<p class="gr-m-0 gr-mt-1 gr-text-sm gr-text-ink-secondary">Текст комментария…</p>
</div>
</div>
<!-- следующий комментарий… -->
</div>
.gr-flex .gr-gap-sm, тексту — .gr-min-w-0Анна Ковалёва
Отступы контейнером — то, чего мне не хватало: стопка комментариев собралась без единого margin.
Даниил Соколов
А фигуре ничего и не нужно: размер держит сам аватар.
Шапка сайта — один флекс-ряд: лого, ссылки, действия. Между соседями
работает .gr-gap, а всё, что после .gr-ms-auto,
уезжает к концу строки (в LTR — к правому краю): авто-маржин съедает
свободное место ряда с одной стороны. Это тот же приём, что
.gr-mx-auto у колонки, только место отдаётся не поровну,
а целиком одной стороне; класс логический, и в RTL шапка развернётся
сама. .gr-flex-wrap — страховка для
совсем узких экранов: когда ряду не хватает места, действия переносятся
на новую строку, а не распирают шапку.
<header class="gr-flex gr-flex-wrap gr-flex-items-center gr-gap gr-px-4 gr-py-2">
<span class="gr-font-bold">Griffin</span>
<nav class="gr-flex gr-gap-sm">
<a href="#">Документация</a>
<a href="#">Примеры</a>
</nav>
<button class="gr-btn gr-btn-primary gr-btn-sm gr-ms-auto">Войти</button>
</header>
.gr-gap между соседями, .gr-ms-auto у действий
В ряду карточек разного объёма кнопки должны стоять на одной горизонтали.
Грид уже растягивает карточки до одной высоты — остаётся прижать низ.
Класса .gr-mt-auto в библиотеке нет, и он не нужен: карточка
становится колонкой .gr-flex .gr-flex-col, а описание
получает .gr-flex-1 и забирает всю разницу высот себе —
футер оказывается у нижнего края. Внутренние поля карточки —
.gr-p-4, зазоры ряда — токен .gr-gap,
который меняется темой вместе с плотностью.
<div class="gr-grid-1 gr-grid-3-md gr-gap">
<div class="gr-flex gr-flex-col gr-p-4">
<h3 class="gr-mb-2">Старт</h3>
<p class="gr-flex-1 gr-mb-4">Короткое описание.</p>
<button class="gr-btn gr-btn-primary">Выбрать</button>
</div>
<div class="gr-flex gr-flex-col gr-p-4">
<h3 class="gr-mb-2">Команда</h3>
<p class="gr-flex-1 gr-mb-4">Описание на три строки — а кнопка всё равно на одной линии с соседями.</p>
<button class="gr-btn gr-btn-primary">Выбрать</button>
</div>
</div>
.gr-flex-1 у описания — не margin-top: autoКороткое описание.
Описание подлиннее, на пару строк, — а кнопка всё равно стоит на одной линии с соседями.
Среднее описание в полторы строки.