Гайды

Как сделать адаптивный размер шрифта — и почему font-size в vw ломает зум

01

Иллюстрация: заголовок плавно растёт вместе с окном, но упирается в два ограничителя

Ты хочешь, чтобы заголовок был крупным на ноутбуке и не вылезал за край на телефоне. Самый короткий путь, который подскажет любой форум, — font-size: 4vw. Четыре процента ширины окна. Растёт вместе с экраном, красота.

Проверь две вещи. На телефоне шириной 360 пикселей это 14 пикселей — заголовок мельче основного текста. На мониторе 2560 — уже 102 пикселя.

А теперь нажми Ctrl и плюс. Зум 200%. Текст не вырос ни на пиксель. Человек, которому нужен крупный шрифт, ничего не может с ним сделать.

Почему так? При зуме браузер делает окно «уже» в CSS-пикселях. Значит, 4vw становится меньше ровно настолько, насколько зум всё увеличил. Одно гасит другое.

Ниже — как сделать по-человечески за пять шагов.

Шаг за шагом: адаптивный шрифт через clamp()

  1. Выбери две точки. Какой размер нужен на самом узком экране и какой на широком. Например, основной текст: 16 пикселей на телефоне 360 и 24 пикселя на ноутбуке 1280. Заголовок: 28 и 48.

  2. Посчитай, как быстро растёт шрифт. Раздели прирост размера на прирост ширины. Для текста: (24 − 16) / (1280 − 360) = 8 / 920 ≈ 0,0087. Умножь на 100 — получишь число для vw: 0,87vw.

  3. Посчитай стартовую добавку. Возьми маленький размер и вычти из него рост на узком экране: 16 − 0,0087 × 360 ≈ 12,87 пикселя. Переведи в rem, разделив на 16: 0,804rem. Почему в rem, а не в пикселях, — объяснено в статье em или rem: rem уважает настройку шрифта в браузере.

  4. Собери clamp(). У него три значения: минимум, плавная середина, максимум.

    body { font-size: clamp(1rem, 0.804rem + 0.87vw, 1.5rem); }
    h1   { font-size: clamp(1.75rem, 1.261rem + 2.174vw, 3rem); }
    

    Браузер берёт середину, но не даёт ей уйти ниже минимума и выше максимума. На 1280 пикселях середина текста даёт ровно 24 — сходится.

  5. Проверь зумом. Открой страницу, нажми Ctrl и плюс до 200%. Текст должен заметно вырасти. Он вырастет примерно в полтора раза, а не вдвое — и это нормально, но только при одном условии из следующего раздела.

Почему важна добавка в rem

Весь фокус — в сумме rem + vw. Часть с vw при зуме сжимается. Часть с rem — растёт. Поэтому в сумме текст всё-таки увеличивается.

Чем больше доля vw, тем слабее рост при зуме. Отсюда простое правило: максимум не больше двух с половиной минимумов. Браузеры позволяют зум до 500%, и при таком соотношении текст гарантированно можно увеличить вдвое — этого требует стандарт доступности WCAG.

У нас: 24 / 16 = 1,5 для текста и 48 / 28 ≈ 1,7 для заголовка. Запас есть. А вот clamp(1rem, 5vw, 4rem) — это 4 к 1, и пользователь с плохим зрением упрётся в потолок.

Чего не делать

  • Не пиши голый vw. font-size: 4vw — это всегда сломанный зум. Даже внутри calc(), если в нём нет rem.
  • Не опускай текст в полях ввода ниже 16 пикселей. Иначе Safari на айфоне сам приближает страницу при тапе в поле. Подробно разобрано в статье почему поле ввода зумит на iPhone. Для input ставь минимум 1rem.
  • Не делай плавным всё подряд. Плавные нужны заголовкам и крупному тексту. Мелкие подписи пусть остаются фиксированными — разница между 12 и 13 пикселями никого не спасёт.

Как удобнее хранить шкалу

Чтобы не копировать формулы по всему CSS, вынеси их в переменные:

:root {
  --step-0: clamp(1rem, 0.804rem + 0.87vw, 1.5rem);
  --step-3: clamp(1.75rem, 1.261rem + 2.174vw, 3rem);
}
h1 { font-size: var(--step-3); }

Как устроены такие переменные, рассказано в статье про CSS-переменные. В Tailwind то же самое пишется прямо в классе: text-[clamp(1.75rem,1.261rem+2.174vw,3rem)].

Что получится

Один набор правил вместо пачки @media с разными размерами. Шрифт плавно растёт от телефона к монитору, не мельчит на узком экране и не раздувается на огромном. И главное — честно увеличивается при зуме.

Нейросеть по умолчанию пишет 4vw или пять медиазапросов. Попроси точно:

Слабый промптсделай шрифт адаптивным
Сильный промптСделай адаптивную шкалу шрифтов через clamp(). Основной текст 16px на ширине 360px и 24px на 1280px, h1 28px и 48px, h2 22px и 34px. Минимум и максимум в rem, середина в виде rem + vw, посчитай по двум точкам. Максимум не больше 2,5 минимумов. Вынеси в CSS-переменные --step-0..--step-3. Без голого vw и без @media для размеров шрифта.

Поддерживают ли clamp() все браузеры?

Да. clamp() работает во всех актуальных браузерах с 2020 года, включая Safari на айфоне. Запасной вариант для старья сегодня обычно не нужен.

Можно ли сделать адаптивный шрифт через медиазапросы?

Можно, но размер будет прыгать ступеньками на каждой границе. clamp() даёт плавный рост одной строкой и не требует помнить, где какая граница.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →