Единицы измерения в CSS: px, em, rem, %, vw и vh
Основы4 минРедакция Innovialabs
Коротко
px — фиксированный размер, rem считается от корневого шрифта, em — от шрифта родителя, % — от родительского блока, vw и vh — от окна; для шрифтов и отступов удобнее rem, для экрана на мобильных — dvh или svh.
Короткий ответ
В CSS есть абсолютные единицы, которые не зависят от окружения, и относительные, которые считаются от чего-то другого: шрифта, родителя или окна браузера.
| Единица | От чего считается | Где удобна |
|---|---|---|
px | Фиксированный CSS-пиксель | Рамки, тени, мелкие детали |
rem | Размер шрифта корневого элемента html | Шрифты, отступы, размеры компонентов |
em | Размер шрифта текущего элемента (для font-size — родителя) | Отступы внутри кнопки, иконки рядом с текстом |
% | Размер родительского блока | Ширина колонок, адаптивные блоки |
vw / vh | 1% ширины / высоты окна | Полноэкранные секции, «плавающая» типографика |
Важно: CSS-пиксель — не физическая точка экрана. На экранах с высокой плотностью один px занимает несколько физических пикселей, поэтому 16px выглядит примерно одинаково на ноутбуке и телефоне.
rem и em: в чём разница и как em накапливается
По умолчанию в браузерах корневой шрифт обычно 16px, значит 1rem = 16px. Если пользователь увеличил шрифт в настройках браузера, все размеры в rem вырастут вместе с ним — это плюс для доступности. Размеры в px такую настройку игнорируют.
rem всегда считается от одного места — html. em считается от ближайшего контекста, и при вложенности значения перемножаются:
.menu { font-size: 1.2em; }
<ul class="menu"> <!-- 16 × 1.2 = 19.2px -->
<li>
<ul class="menu"> <!-- 19.2 × 1.2 = 23.04px -->
<li>Пункт</li>
</ul>
</li>
</ul>
Каждый вложенный уровень становится крупнее — частая причина «необъяснимо огромного» текста. С 1.2rem все уровни были бы одинаковыми.
Зато em полезен там, где размер должен следовать за текстом: padding: 0.5em 1em у кнопки сохраняет пропорции, если поменять ей font-size.
Проценты: от чего именно
% почти всегда считается от родительского блока, но есть нюансы:
width: 50%— половина ширины родителя.height: 50%работает, только если у родителя задана высота.paddingиmarginв процентах считаются от ширины родителя, даже вертикальные.font-size: 120%— то же самое, что1.2em.
vw, vh и проблема 100vh на мобильных
1vw — 1% ширины окна, 1vh — 1% высоты. Кажется, что height: 100vh даёт ровно один экран. На десктопе это так, но на мобильных браузерах адресная строка и панели то появляются, то прячутся. vh обычно равен высоте окна при скрытых панелях, поэтому при открытой адресной строке низ блока уходит за край, и кнопка внизу экрана оказывается не видна.
Современные единицы решают проблему:
svh— малая высота окна, когда все панели видны. Блок гарантированно помещается.lvh— большая высота, когда панели скрыты (как старыйvh).dvh— динамическая высота, меняется вместе с панелями.
.hero {
min-height: 100vh; /* запасной вариант для старых браузеров */
min-height: 100svh; /* надёжно помещается на мобильных */
}
dvh точнее, но при прокрутке блок может менять высоту и «прыгать». Для первого экрана чаще выбирают svh, dvh — для полноэкранных модальных окон.
Ещё одна ловушка: на десктопе 100vw включает ширину полосы прокрутки, поэтому width: 100vw может вызвать горизонтальный скролл. Для полной ширины обычно достаточно width: 100%.
Практическое правило
- Шрифты — в
rem. Для заголовков, которые растут вместе с экраном, —clamp():font-size: clamp(2rem, 5vw, 4rem). - Отступы и размеры компонентов — в
rem, внутренние отступы, зависящие от текста, — вem. - Раскладка —
%,frв grid, flex; фиксированные ширины вpx— только какmax-width. - Рамки, тени, тонкие линии — в
px. - Высота экрана —
svhилиdvhс запаснымvh.
Частые ошибки
- Задавать
font-sizeвemна вложенных компонентах и получать накопление. - Жёсткая
heightвpxдля блока с текстом — при увеличении шрифта текст вылезает. 100vhдля первого экрана на мобильных безsvh.- Менять корневой размер на
62.5%ради «удобных»remи забывать, что это ломает сторонние компоненты.