Что такое…

em или rem — в чём разница и что выбрать

Иллюстрация: вложенные ящики, у каждого своя линейка внутри — и одна длинная латунная линейка, привинченная к столу

Есть факт, который переворачивает спор «em или rem» с ног на голову: в медиазапросах обе единицы работают одинаково — и обе игнорируют то, что ты написал в html. Так и записано в спецификации медиазапросов.

То есть половина различий, из-за которых их сравнивают, там просто не существует. А там, где существует, разница вполне конкретная. Разберём по пунктам.

Коротко: от чего считается каждая

em считается от размера шрифта «в этом месте». Тонкость: для свойства font-size это шрифт родителя, для всего остального (padding, margin, width) — шрифт самого элемента.

rem считается от размера шрифта корневого элемента, то есть html. Одна точка отсчёта на весь документ. По умолчанию это обычно 16px, но пользователь может поменять значение в настройках браузера — и тогда поменяется твой 1rem.

Сравнение по тем критериям, которые реально решают

Точка отсчёта. У rem она одна и глобальная. У em — локальная и своя у каждого элемента. Отсюда всё остальное.

Предсказуемость. 1.5rem — это всегда одно и то же, где бы ты его ни написал. 1.5em придётся считать в уме, зная контекст. В большом проекте это разница между «посмотрел и понял» и «открыл инспектор».

Вложенность. Тут em кусается. Задай li { font-size: 0.9em } — и в списке внутри списка получится 0.81em, на третьем уровне 0.729em. Текст тает с каждым уровнем. Это называется компаундингом, и это самая частая причина «почему у меня где-то текст мелкий». У rem такого не бывает по определению.

Масштабирование компонента целиком. А тут выигрывает em. Опиши кнопку через padding: 0.6em 1.2em — и когда ты поменяешь только её font-size, отступы вырастут пропорционально. Одна переменная вместо трёх. Для rem пришлось бы править каждое значение.

Уважение к пользователю. Обе единицы в итоге опираются на настройку размера шрифта в браузере, поэтому обе — честный выбор с точки зрения доступности. А вот px эту настройку игнорирует: человек увеличил шрифт в браузере, а твой текст остался прежним.

Медиазапросы. Тот самый сюрприз. По спецификации относительные единицы внутри медиазапроса считаются от начального значения font-size, а не от того, что ты задал в стилях. Написал html { font-size: 62.5% } (то есть 10px) — в правилах 1rem станет 10px, а в @media (min-width: 40rem) порог останется 640-ю пикселями, как будто ты ничего не менял. Сюда же и em: в медиазапросах они эквивалентны.

Как быстро считать в уме

При стандартных 16 пикселях шкала запоминается за минуту:

  • 0.75rem — 12px, мелкие подписи;
  • 0.875rem — 14px, вторичный текст;
  • 1rem — 16px, основной текст;
  • 1.25rem — 20px, подзаголовок;
  • 2rem — 32px, заголовок.

Дальше арифметика простая: нужное число пикселей делишь на 16. И не гонись за круглыми значениями — 0.9375rem ничем не хуже, просто выглядит непривычно.

С em такой шкалы не построить: пока не знаешь шрифт родителя, число ни о чём не говорит. Отсюда и практический совет — держи em там, где кегль задан рядом, буквально в соседней строке того же правила.

Кому что подойдёт

Без увиливаний:

  • rem — для всего, что задаёт масштаб страницы: размеры шрифтов, вертикальные отступы между блоками, ширины контейнеров. Предсказуемо и не накапливает ошибку.
  • em — внутри компонента: отступы кнопки, поля, бейджа. Тогда компонент остаётся «резиновым» относительно собственного кегля, и его легко сделать крупнее одной строчкой.
  • px — для того, что не должно расти: рамка в 1 пиксель, толщина тени, иконка фиксированного размера.

Если сомневаешься — бери rem. Ошибка с ним стоит дешевле: текст будет чуть не того размера. Ошибка с em прячется во вложенности и вылезает через месяц.

Можно ли поставить html font-size: 10px, чтобы считать было проще?

Так делают, чтобы 1.6rem читалось как «16 пикселей». Но абсолютное значение в html затирает настройку пользователя: человек выбрал в браузере крупный шрифт, а ты вернул ему 10px. Если очень хочется — используй 62.5%: проценты считаются от пользовательского значения и масштабируются вместе с ним. И помни про медиазапросы — на них этот трюк не действует.

А px вообще нельзя?

Можно, просто не для текста. Для рамок, теней и мелкой графики пиксели удобнее и честнее. Проблема только там, где значение должно расти вместе с настройками человека.

Чему равен 1rem по умолчанию?

В большинстве браузеров 16px — но это именно значение по умолчанию, а не константа. Пользователь может задать другое, и тогда весь макет на rem вырастет вместе с ним. Проверить, что получилось в итоге, всегда можно в инспекторе: вкладка Computed показывает конечные пиксели. Кстати, 16px — не случайное число и в другой истории: почему iPhone увеличивает страницу на поле ввода. А высота строки — единственное место, где единицы лучше не писать вовсе: как работает line-height. Если же значения вроде заданы, а в браузере всё по-старому — начни с базовых причин: почему CSS не применяется.

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

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

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

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

Все статьи →