Действуй как дизайн-систем инженер. Настрой fluid typography через clamp() для всех уровней шрифтов и spacing-токенов. Диапазон viewport: {{min_viewport}}–{{max_viewport}}px.
1. Анатомия clamp()
clamp(MIN, PREFERRED, MAX)
- MIN — нижняя граница (на самом узком экране)
- PREFERRED — целевое значение, обычно зависящее от viewport
- MAX — верхняя граница (на самом широком экране)
Браузер выбирает: если PREFERRED < MIN → MIN; если > MAX → MAX; иначе — PREFERRED.
2. Формула preferred
Цель: значение растёт линейно от MIN на узком экране до MAX на широком.
slope = (MAX - MIN) / (MAX_VW - MIN_VW)
intercept = MIN - slope * MIN_VW
preferred = calc({intercept}rem + {slope * 100}vw)
Пример: H1 16px → 48px от 320 до 1440
- MIN = 16px = 1rem
- MAX = 48px = 3rem
- slope = (48 - 16) / (1440 - 320) = 0.0286
- intercept = 16 - 0.0286 × 320 = 6.86px = 0.429rem
h1 { font-size: clamp(1rem, 0.429rem + 2.86vw, 3rem); }
Готовая mixin-функция (SCSS):
@function fluid($min, $max, $min-vw: 320, $max-vw: 1440) {
$slope: ($max - $min) / ($max-vw - $min-vw);
$intercept: $min - $slope * $min-vw;
@return clamp(#{$min}px, #{$intercept}px + #{$slope * 100}vw, #{$max}px);
}
h1 { font-size: fluid(16, 48); }
h2 { font-size: fluid(14, 32); }
3. Type scale
:root {
--fs-xs: clamp(0.75rem, 0.71rem + 0.18vw, 0.875rem); /* 12 → 14 */
--fs-sm: clamp(0.875rem, 0.83rem + 0.22vw, 1rem); /* 14 → 16 */
--fs-md: clamp(1rem, 0.93rem + 0.36vw, 1.25rem); /* 16 → 20 */
--fs-lg: clamp(1.25rem, 1.12rem + 0.63vw, 1.625rem); /* 20 → 26 */
--fs-xl: clamp(1.625rem, 1.39rem + 1.16vw, 2.25rem); /* 26 → 36 */
--fs-2xl: clamp(2.25rem, 1.82rem + 2.14vw, 3.5rem); /* 36 → 56 */
--fs-3xl: clamp(2.75rem, 1.96rem + 3.93vw, 5rem); /* 44 → 80 */
}
4. Spacing tokens — туда же
:root {
--space-1: clamp(0.25rem, 0.23rem + 0.09vw, 0.3125rem); /* 4 → 5 */
--space-2: clamp(0.5rem, 0.46rem + 0.18vw, 0.625rem); /* 8 → 10 */
--space-4: clamp(1rem, 0.92rem + 0.36vw, 1.25rem); /* 16 → 20 */
--space-8: clamp(2rem, 1.71rem + 1.43vw, 2.75rem); /* 32 → 44 */
--space-16: clamp(4rem, 3.14rem + 4.29vw, 6.25rem); /* 64 → 100 */
}
5. Edge cases
Ультра-узкий (≤ 320px)
Старый iPhone SE первого поколения, фичефоны в landscape. Если MIN = 16px — текст всё равно читаем. Если поставил MIN = 14px на body → проблема, минимум для body = 16px (см. accessibility).
Ультра-широкий (4K, 27"+)
На 3840px viewport vw уходит в космос. Без MAX H1 станет 120px+. Всегда задавай MAX. Опционально: ограничь весь сайт через max-width: 1440px на body — тогда vw считается от ограниченной ширины.
Сжатие zoom 200%
Если использовать только vw без rem в preferred — зум сломан, шрифт не реагирует. Поэтому формула всегда {rem} + {vw}. Это требование WCAG 1.4.4.
Между MIN и MAX viewport
Между 320 и 1440 значение растёт линейно. Хочешь S-curve? Используй несколько clamp через @container или CSS min()/max() композиции.
6. Accessibility
- Body text: MIN ≥ 16px. Меньше — нарушение WCAG 1.4.4 для большинства пользователей.
- Не клампь
line-heightв абсолютных единицах. Юзай unitless (line-height: 1.5) — масштабируется само. - Caption / помощь: MIN ≥ 14px. Меньше — только для уникальных лейблов, никогда для body content.
- Headings: можно агрессивнее (H1 12px на 320 — окей), но проверь, что иерархия читается.
- Зум 200%: проверь через DevTools → Settings → Zoom 200%. Текст должен расти, а не быть зафиксирован.
7. Формат вывода
## Fluid type scale
| Token | MIN (320px) | MAX (1440px) | Formula |
|---|---|---|---|
| --fs-md | 16px | 20px | clamp(1rem, 0.93rem + 0.36vw, 1.25rem) |
## Spacing scale
[аналогично]
## Validation
- [ ] Body ≥ 16px на 320px
- [ ] Зум 200% — текст растёт
- [ ] 4K — текст не уходит в космос
- [ ] line-height unitless везде
Anti-patterns
- ❌
font-size: 3vwбез clamp — на 320px = 9.6px (нечитаемо), на 4K = 115px (карикатурно). - ❌ Preferred без
rem, толькоvw— зум 200% не работает, провал WCAG 1.4.4. - ❌ MIN < 16px на body — половина читателей со средним зрением страдает.
- ❌ Один
clampдля всей типографики — крошечный H6 = 12px и здоровенный H1 = 72px не сделаешь одной формулой, нужна шкала. - ❌
line-height: clamp(20px, ...)— фиксированные единицы в line-height, при изменении font-size — рассинхрон. Используйline-height: 1.5. - ❌ Расчёт slope вручную для каждого токена — ошибки, забытые знаки. SCSS-функция или CSS
calc()с переменными. - ❌ Игнор ультра-широкого — без MAX дизайн на 27" мониторе выглядит сломанно, типографика плывёт.
- ❌ Fluid spacing БЕЗ fluid type — текст растёт, паддинги фиксированы, ритм рушится. Либо всё, либо ничего.
Mobile-friendly аудит (375px)
Аудит мобильной версии на iPhone SE: тач-таргеты, скролл, попапы, tap-vs-hover, input zoom.
Brand guidelines с нуля
Сборка полного гайдлайна: voice, color tokens, типографика, правила логотипа, антипаттерны и примеры. Готовый DESIGN.md.
Дизайн-токены из референса
Извлечь систему цветов, типографики, теней, радиусов и spacing из примера и оформить как токены.