Как типографика влияет на восприятие
Правильно подобранный шрифт и интервал улучшают читаемость и удержание внимания — а этот хвост анонса уже спрятан за многоточием, потому что в карточке ему не место.
Полный набор типографических утилит: размеры абсолютные и относительные, насыщенность, выравнивание, трансформация, межстрочный интервал, декор, переносы и шрифтовые семейства. Классы имеют адаптивные варианты с суффиксами -sm, -md, -lg, -xl — кроме относительных размеров.
| Переменная | Значение | Назначение |
|---|---|---|
--gr-font-sans |
system-ui, -apple-system, sans-serif |
Семейство без засечек |
--gr-font-serif |
Georgia, Cambria, serif |
Семейство с засечками |
--gr-font-mono |
SFMono-Regular, Menlo, Consolas, monospace |
Моноширинное семейство |
--gr-font-size-base |
1rem |
Базовый размер шрифта |
10 размеров от 12px до 60px. Генерируются SCSS-циклом по карте (xs: 0.75rem, sm: 0.875rem, ...).
| Класс | REM | PX |
|---|---|---|
.gr-text-xs | 0.75rem | 12px |
.gr-text-sm | 0.875rem | 14px |
.gr-text-base | 1rem | 16px |
.gr-text-lg | 1.125rem | 18px |
.gr-text-xl | 1.25rem | 20px |
.gr-text-2xl | 1.5rem | 24px |
.gr-text-3xl | 1.875rem | 30px |
.gr-text-4xl | 2.25rem | 36px |
.gr-text-5xl | 3rem | 48px |
.gr-text-6xl | 3.75rem | 60px |
<p class="gr-text-xs">12px — подписи, сноски</p>
<p class="gr-text-sm">14px — вспомогательный текст</p>
<p class="gr-text-base">16px — основной текст</p>
<h3 class="gr-text-2xl">24px — подзаголовок</h3>
<h1 class="gr-text-5xl">48px — крупный заголовок</h1>
Подписи, сноски, мелкий вспомогательный текст
Вспомогательный текст, описания полей
Основной текст документа, body
Укрупнённый текст, лиды
Подзаголовки
Заголовки разделов
Крупные заголовки
Герой-секции
Главный заголовок страницы
Лендинги, промо
Базовые .gr-text-* считают размер в rem — от корня документа,
независимо от окружения. Для страницы это правильно, но неудобно для блока, который
показывают в разных местах шаблона: виджет в шапке и он же в подвале должны отличаться
размером, а содержимое у них одно. То же с текстом, подгружаемым из БД: на этапе вёрстки
неизвестно, куда его вставят.
.gr-text-rel-* не задают размер, а сдвигают текущий на фиксированный шаг
в пикселях. Шаг взят в пикселях, а не долей em, намеренно: от базовых 16px
четыре младшие ступени попадают в базовую шкалу ровно, без округлений.
| Класс | Значение | При родителе 16px |
|---|---|---|
.gr-text-rel-xs | calc(1em - 4px) | 12px — как .gr-text-xs |
.gr-text-rel-sm | calc(1em - 2px) | 14px — как .gr-text-sm |
.gr-text-rel-lg | calc(1em + 2px) | 18px — как .gr-text-lg |
.gr-text-rel-xl | calc(1em + 4px) | 20px — как .gr-text-xl |
.gr-text-rel-2xl | calc(1em + 6px) | 22px |
.gr-text-rel-3xl | calc(1em + 8px) | 24px |
Ступени base в наборе нет: класс, не меняющий размер, не нужен — его роль
играет отсутствие класса. Шкала обрывается на 3xl: крупнее — это уже не
подстройка блока под окружение, а отдельный заголовок, для которого есть базовый набор.
<!-- разметка виджета одна, размер задаёт только класс на корне -->
<article class="gr-text-sm">
<h4 class="gr-text-rel-xl">Заголовок виджета</h4>
<p>Текст из БД</p>
<p class="gr-text-rel-xs">Сноска</p>
</article>
Текст, подгружаемый из БД. Размер сдвигается вместе с корнем блока.
Сноска
Текст, подгружаемый из БД. Размер сдвигается вместе с корнем блока.
Сноска
Четыре особенности, о которых стоит помнить:
.gr-text-rel-sm даст 30px, а не 28px. Это плата за точное попадание
в шкалу от базовых 16px..gr-text-rel-sm
внутри .gr-text-rel-sm — это −4px суммарно. Это и есть смысл набора:
блок сдвигается целиком. Каскадировать его глубже двух уровней обычно не нужно..gr-text-* внутри обрывает цепочку. Он в
rem и вернёт абсолютный размер независимо от родителя. Смешивать оба набора
в одном поддереве — верный способ получить неожиданный результат..gr-text-rel-* внутри, а размер корня меняйте контейнерным
.gr-text-sm-cmd.9 значений font-weight от 100 до 900. Генерируются SCSS-циклом по карте.
| Класс | Значение | Роль |
|---|---|---|
.gr-font-thin | 100 | Сверхтонкий |
.gr-font-extralight | 200 | Очень тонкий |
.gr-font-light | 300 | Тонкий |
.gr-font-normal | 400 | Нормальный (по умолчанию) |
.gr-font-medium | 500 | Средний |
.gr-font-semibold | 600 | Полужирный |
.gr-font-bold | 700 | Жирный |
.gr-font-extrabold | 800 | Очень жирный |
.gr-font-black | 900 | Сверхжирный |
<span class="gr-font-light">Тонкий текст</span>
<span class="gr-font-semibold">Полужирный текст</span>
<span class="gr-font-bold">Жирный текст</span>
Griffincss — модульная типографика
Griffincss — модульная типографика
Griffincss — модульная типографика
Griffincss — модульная типографика
Griffincss — модульная типографика
Griffincss — модульная типографика
Griffincss — модульная типографика
Griffincss — модульная типографика
Четыре класса text-align: центр, ширина и логические стороны строки.
| Класс | Значение | В RTL |
|---|---|---|
.gr-text-center | text-align: center | по центру |
.gr-text-justify | text-align: justify | по ширине |
.gr-text-start | text-align: start | справа |
.gr-text-end | text-align: end | слева |
start и end — начало и конец строки, а не
сторона экрана: в LTR это левый и правый край, в RTL они меняются
местами сами. Физические .gr-text-left /
.gr-text-right удалены: сторона текста следует
за направлением письма, а буквальная сторона задаётся своим CSS.
<p class="gr-text-start">По началу строки</p>
<p class="gr-text-center">По центру</p>
<p class="gr-text-end">По концу строки</p>
<p class="gr-text-justify">По ширине с растяжением пробелов</p>
dir="rtl" тот же класс выровняет текст справа.| Класс | Значение |
|---|---|
.gr-uppercase | text-transform: uppercase |
.gr-lowercase | text-transform: lowercase |
.gr-capitalize | text-transform: capitalize |
<span class="gr-uppercase">все буквы заглавные</span>
<span class="gr-lowercase">ВСЕ БУКВЫ СТРОЧНЫЕ</span>
<span class="gr-capitalize">каждое слово с заглавной</span>
griffincss typography module — все буквы заглавные
GRIFFINCSS TYPOGRAPHY MODULE — ВСЕ БУКВЫ СТРОЧНЫЕ
griffincss typography module — каждое слово с заглавной
5 значений line-height.
| Класс | Значение | Применение |
|---|---|---|
.gr-leading-tight | 1.25 | Крупные заголовки |
.gr-leading-snug | 1.375 | Подзаголовки |
.gr-leading-normal | 1.5 | Основной текст |
.gr-leading-relaxed | 1.625 | Длинные тексты, статьи |
.gr-leading-loose | 2 | Разреженный текст, поэзия |
<p class="gr-text-sm gr-leading-tight">Плотный интервал — для заголовков</p>
<p class="gr-text-sm gr-leading-normal">Нормальный интервал — для основного текста</p>
<p class="gr-text-sm gr-leading-loose">Свободный интервал — для разреженного текста</p>
Плотный межстрочный интервал хорошо подходит для крупных заголовков, где строки должны быть визуально сгруппированы. Несколько строк текста с плотным интервалом.
Нормальный межстрочный интервал — стандарт для основного текста. Обеспечивает комфортное чтение. Несколько строк с нормальным интервалом.
Свободный межстрочный интервал создаёт воздух между строками. Используется для поэзии, цитат или разреженного текста. Двойной интервал.
| Класс | Значение |
|---|---|
.gr-underline | text-decoration: underline |
.gr-no-underline | text-decoration: none |
.gr-line-through | text-decoration: line-through |
.gr-italic | font-style: italic |
.gr-not-italic | font-style: normal |
.gr-tabular-nums | font-variant-numeric: tabular-nums — цифры одной ширины, разряды в колонке чисел стоят друг под другом |
<span class="gr-underline">Подчёркнутый текст</span>
<span class="gr-line-through">Зачёркнутый текст</span>
<em>Курсив, и только <span class="gr-not-italic">эта часть</span> прямая</em>
<span class="gr-italic">Курсивный текст</span>
<a class="gr-no-underline">Ссылка без подчёркивания</a>
Подчёркнутый текст — для ссылок и акцентов
Зачёркнутый текст — старая цена, удалённое
Курсивный текст — цитаты, термины, акцент
Весь этот текст в <em> — курсив, и только эти три слова выпрямлены
1 111 111 ₽ и 8 888 888 ₽ — одной ширины; в колонке сумм таблицы разряды не гуляют
| Класс | Свойства |
|---|---|
.gr-break-words | overflow-wrap: break-word |
.gr-truncate | overflow: hidden; text-overflow: ellipsis; white-space: nowrap |
.gr-whitespace-nowrap | white-space: nowrap |
.gr-whitespace-pre | white-space: pre |
.gr-whitespace-normal | white-space: normal |
<p class="gr-break-words">
ДлинныйURLилиСловоБезПробеловКотороеНеПомещаетсяВКонтейнер
</p>
<p class="gr-truncate">
Очень длинный текст который обрезается многоточием когда не помещается в одну строку
</p>
SuperLongUnbreakableWordWithoutSpacesThatWrapsAutomatically
Очень длинный текст который не помещается в одну строку и обрезается многоточием
Текст не переносится на новую строку никогда
| Класс | CSS | Где уместен |
|---|---|---|
.gr-text-balance | text-wrap: balance | Заголовки: браузер выравнивает длину строк, последняя не остаётся из одного слова |
.gr-text-pretty | text-wrap: pretty | Абзацы: убираются висячие слова в конце |
balance рассчитан на короткий текст — браузеры применяют его
к нескольким первым строкам, поэтому для длинных абзацев берите
pretty.
<h2 class="gr-text-balance">Заголовок в две строки, разбитый поровну</h2>
<p class="gr-text-pretty">Длинный абзац без висячих слов…</p>
.gr-line-clamp-{1…6} обрезает текст после указанного числа
строк и ставит многоточие. В отличие от .gr-truncate, который
работает только на одной строке, здесь текст переносится нормально.
| Класс | Результат |
|---|---|
.gr-line-clamp-1 … .gr-line-clamp-6 | Не больше N строк, дальше — многоточие |
.gr-line-clamp-none | Снять обрезку |
Описание товара, которое в исходнике занимает четыре строки, а в карточке должно занимать ровно две — иначе карточки в ряду разъедутся по высоте и сетка перестанет читаться как сетка. Вот эта часть текста уже не видна.
<p class="gr-line-clamp-2">Описание товара…</p>
Ресет снимает маркеры только со списков, размеченных как
role="list" — обычный <ul> в тексте
сохраняет и маркеры, и отступ. Эти классы меняют оформление там,
где разметку трогать нельзя.
| Класс | CSS |
|---|---|
.gr-list-none | list-style: none; padding-inline-start: 0 |
.gr-list-disc | list-style: disc |
.gr-list-decimal | list-style: decimal |
.gr-list-inside | list-style-position: inside |
.gr-list-outside | list-style-position: outside |
Безусловный list-style: none лишает <ul>
роли списка в VoiceOver, а вместе с ней — озвучки «список из N элементов».
Атрибут role="list" возвращает роль, оставляя оформление
снятым: <ul role="list" class="gr-flex gr-gap"> — то, что
нужно навигации.
Три класса, ссылающиеся на CSS-переменные --gr-font-*. Переопределите переменные для кастомных шрифтов.
| Класс | Значение |
|---|---|
.gr-font-sans | var(--gr-font-sans) |
.gr-font-serif | var(--gr-font-serif) |
.gr-font-mono | var(--gr-font-mono) |
<p class="gr-font-sans">system-ui, -apple-system, sans-serif</p>
<p class="gr-font-serif">Georgia, Cambria, serif</p>
<p class="gr-font-mono">SFMono-Regular, Menlo, Consolas, monospace</p>
Griffincss — The quick brown fox jumps over the lazy dog. 1234567890.
Griffincss — The quick brown fox jumps over the lazy dog. 1234567890.
Griffincss — The quick brown fox jumps over the lazy dog. 1234567890.
Классы выше имеют варианты с суффиксом брейкпоинта: -sm (≥640px), -md (≥768px),
-lg (≥1024px), -xl (≥1280px). Размер шрифта, насыщенность, выравнивание,
трансформация, интервал, декор, переносы и семейство — любые свойства можно менять на разных разрешениях.
Исключение — относительные размеры .gr-text-rel-*: у них вариантов нет,
размер там задаёт вложенность, а не ширина окна.
<!-- Базовый размер sm, от 768px становится lg, от 1024px — xl -->
<p class="gr-text-sm gr-text-lg-md gr-text-xl-lg">
Адаптивный размер шрифта
</p>
<!-- На мобильных — по началу строки, от 1024px — по центру -->
<h2 class="gr-text-start gr-text-center-lg">
Адаптивное выравнивание
</h2>
<!-- Нормальная насыщенность, от 768px — жирный -->
<span class="gr-font-normal gr-font-bold-md">
Адаптивная насыщенность
</span>
Этот текст меняет размер на разных разрешениях: 14px → 18px (≥768px) → 20px (≥1024px)
Нормальная насыщенность на мобильных, жирный от 768px
// _typography.scss — все утилиты генерируются циклами
// Размеры
$gr-text-sizes: (
xs: 0.75rem, sm: 0.875rem, base: 1rem,
lg: 1.125rem, xl: 1.25rem, 2xl: 1.5rem,
3xl: 1.875rem, 4xl: 2.25rem, 5xl: 3rem, 6xl: 3.75rem
);
@each $name, $size in $gr-text-sizes {
.gr-text-#{$name} { font-size: $size; }
}
// Относительные размеры — шаг в px от текущего размера
$gr-text-rel-steps: (
xs: -4px, sm: -2px, lg: 2px,
xl: 4px, 2xl: 6px, 3xl: 8px
);
@each $gr-name, $gr-delta in $gr-text-rel-steps {
.gr-text-rel-#{$gr-name} {
@if $gr-delta < 0 {
font-size: calc(1em - #{math.abs($gr-delta)});
} @else {
font-size: calc(1em + #{$gr-delta});
}
}
}
// Насыщенность
$gr-weights: (
"thin": 100, "extralight": 200, "light": 300,
"normal": 400, "medium": 500, "semibold": 600,
"bold": 700, "extrabold": 800, "black": 900
);
@each $name, $weight in $gr-weights {
.gr-font-#{$name} { font-weight: $weight; }
}
// Адаптивные варианты генерируются для всех групп
@each $bp-name, $bp-value in $gr-breakpoints {
@media (width >= $bp-value) {
@each $name, $size in $gr-text-sizes {
.gr-text-#{$name}-#{$bp-name} { font-size: $size; }
}
// ... остальные группы аналогично
}
}
Комбинируйте классы. gr-text-lg gr-font-bold gr-leading-tight — три класса дают готовый заголовок. Не нужно писать отдельные CSS-правила для каждого элемента.
Переопределяйте переменные. Хотите кастомный шрифт? --gr-font-sans: 'Inter', sans-serif; на :root — и все .gr-font-sans подхватят его автоматически.
Аккуратно с gr-truncate. Класс обрезает текст и скрывает его. Не используйте на элементах, где важна полная доступность контента. Для многострочного усечения есть .gr-line-clamp-1…6 — см. «Обрезка по числу строк».
Типографика редко живёт одна: заголовок стоит над подводкой ограниченной ширины, пункт списка начинается с цветной галочки, метастрока собирается флексом. Рецепты ниже — самые ходовые текстовые блоки, собранные из этого модуля вместе с цветами, отступами и флексом ядра.
Первый экран лендинга держится на контрасте трёх ступеней. Заголовок —
крупный и плотный: .gr-text-4xl .gr-text-5xl-md (на телефоне
меньше), .gr-font-extrabold, .gr-leading-tight,
а .gr-text-balance просит браузер разбить строки поровну,
чтобы последняя не осталась из одного слова. Ключевое слово выделяется
простым span с .gr-text-primary — градиентной
заливки текста в библиотеке нет, акцент делается цветом. Подводка —
тише и ýже: .gr-text-lg .gr-text-ink-secondary с пределом
.gr-max-w-[55ch], чтобы строка оставалась читаемой.
Ряд кнопок — .gr-flex .gr-gap-sm .gr-flex-center.
<section class="gr-text-center gr-py-12">
<h1 class="gr-text-4xl gr-text-5xl-md gr-font-extrabold gr-leading-tight gr-text-balance gr-mb-4">
Вёрстка <span class="gr-text-primary">без борьбы</span> с CSS
</h1>
<p class="gr-text-lg gr-text-ink-secondary gr-text-pretty gr-max-w-[55ch] gr-mx-auto gr-mb-6">
Модульная библиотека утилит: подключаете только нужное,
собираете интерфейс из готовых классов.
</p>
<div class="gr-flex gr-gap-sm gr-flex-center">
<button class="gr-btn gr-btn-primary gr-btn-lg">Начать</button>
<button class="gr-btn gr-btn-ghost gr-btn-lg">Документация</button>
</div>
</section>
.gr-text-* + .gr-text-balance на заголовкеМодульная библиотека утилит: подключаете только нужное, собираете интерфейс из готовых классов.
Список преимуществ в прайсинге или feature-секции — это
<ul role="list"> (ресет снимает маркеры, роль остаётся
для скринридеров), где каждый пункт — мини медиа-объект:
.gr-flex .gr-gap-sm .gr-flex-items-start. Галочка —
обычный символ с .gr-text-success .gr-font-bold; выравнивание
по верху не даёт второй строке текста залезть под неё. Текст пунктов
приглушён токеном .gr-text-ink-secondary — цвет чернил
из темы, а не серый из палитры.
<ul role="list" class="gr-flex gr-flex-col gr-gap-sm">
<li class="gr-flex gr-gap-sm gr-flex-items-start">
<span class="gr-text-success gr-font-bold">✓</span>
<span class="gr-text-ink-secondary">Все модули независимы</span>
</li>
<li class="gr-flex gr-gap-sm gr-flex-items-start">
<span class="gr-text-success gr-font-bold">✓</span>
<span class="gr-text-ink-secondary">Тёмная тема из коробки</span>
</li>
</ul>
.gr-flex .gr-gap-sm .gr-flex-items-start, галочка не пускает текст под себя
Редакционная цитата собирается из трёх модулей: линия слева —
.gr-border-s-4 .gr-border-primary из бордеров (логическая
сторона s — в RTL линия сама перейдёт направо), воздух
от линии — .gr-ps-4 из спейсинга, а голос цитаты — курсив
.gr-italic с укрупнённым .gr-text-lg. Подпись
автора — ступенькой ниже и тише: .gr-text-sm .gr-text-ink-secondary
.gr-not-italic, чтобы выйти из курсива родителя.
<blockquote class="gr-border-s-4 gr-border-primary gr-ps-4 gr-italic gr-text-lg">
<p class="gr-mb-2">Хорошая типографика незаметна — замечают только плохую.</p>
<footer class="gr-not-italic gr-text-sm gr-text-ink-secondary">— Анна Ковалёва, дизайнер</footer>
</blockquote>
.gr-not-italicХорошая типографика незаметна — замечают только плохую.
Stats-секция строится на контрасте кеглей в паре «число — подпись»:
число в три-четыре раза крупнее (.gr-text-4xl .gr-font-extrabold),
подпись — мелкая и разреженная (.gr-text-xs .gr-uppercase
.gr-text-ink-secondary). Ряд из трёх пар держит грид
.gr-grid-1 .gr-grid-3-sm. Утилиты табличных цифр
в библиотеке нет: она нужна только «тикающим» счётчикам, а там
font-variant-numeric: tabular-nums задаётся обычным CSS.
<div class="gr-grid-1 gr-grid-3-sm gr-gap gr-text-center">
<div>
<p class="gr-m-0 gr-text-4xl gr-font-extrabold gr-text-primary">12 000+</p>
<p class="gr-m-0 gr-mt-1 gr-text-xs gr-uppercase gr-text-ink-secondary">Проектов</p>
</div>
…
</div>
12 000+
Проектов
99,9 %
Аптайм
4,8
Средняя оценка
Карточка блога — концентрат модуля: рубрика-надзаголовок
(.gr-text-xs .gr-uppercase .gr-font-semibold цветом акцента),
заголовок с плотным интервалом, анонс, обрезанный на второй строке
.gr-line-clamp-2, — благодаря ему карточки в сетке остаются
одной высоты. Метастрока внизу — флекс с аватаром из ui и разделителями:
мелкий кегль и приглушённый цвет отделяют служебное от главного.
<article>
<span class="gr-text-xs gr-uppercase gr-font-semibold gr-text-accent">Дизайн</span>
<h3 class="gr-text-2xl gr-font-bold gr-leading-tight gr-mt-2 gr-mb-3">
Как типографика влияет на восприятие
</h3>
<p class="gr-line-clamp-2 gr-text-sm gr-text-ink-secondary">Анонс, обрезанный на второй строке…</p>
<footer class="gr-flex gr-flex-items-center gr-gap-sm gr-mt-4 gr-text-xs gr-text-ink-secondary">
<span class="gr-avatar gr-avatar-sm">ИП</span>
<span class="gr-font-medium">Иван Петров</span>
<span>·</span>
<span>5 мин чтения</span>
</footer>
</article>
.gr-line-clamp-2 — карточки в сетке не разъезжаютсяПравильно подобранный шрифт и интервал улучшают читаемость и удержание внимания — а этот хвост анонса уже спрятан за многоточием, потому что в карточке ему не место.
Три величины в одной строке, и каждая своим приёмом. Цена — крупная
и плотная: .gr-text-3xl .gr-font-bold .gr-leading-tight.
Старая — тише и зачёркнута: <s>
с .gr-line-through .gr-text-ink-secondary. Размер скидки —
плашка .gr-badge .gr-badge-danger, то есть слово
«−25 %», а не только красный цвет. Ряд — .gr-flex
с выравниванием по базовой линии: цифры разного кегля обязаны стоять
на одной линии, а не по центру своих коробок.
<s>, а не <span>: элемент означает
«уже не актуально» — ровно то, что случилось со старой ценой. Зачёркивание
при этом остаётся признаком для глаза, поэтому перед числом стоит
.gr-sr-only со словом «старая цена»: скринридер линию
не объявляет, и без него обе цены прозвучали бы подряд без разницы.
<p class="gr-flex gr-flex-items-baseline gr-flex-wrap gr-gap-sm gr-m-0">
<span class="gr-text-3xl gr-font-bold gr-leading-tight">12 990 ₽</span>
<s class="gr-line-through gr-text-ink-secondary">
<span class="gr-sr-only">Старая цена </span>17 320 ₽
</s>
<span class="gr-badge gr-badge-danger">−25 %</span>
</p>
12 990 ₽
Старая цена 17 320 ₽
−25 %
2 450 ₽ за упаковку
Классов .gr-price и .gr-price-old
здесь нет намеренно. Обе строки собираются из кегля, веса,
цвета чернил и плашки — всё это уже есть и работает в обеих темах.
Новое имя не добавило бы ни одного свойства, зато завело бы второй
способ сказать «крупный полужирный текст» и потребовало бы решать,
что такое цена в валюте без копеек, в рассрочку и за килограмм.