Единицы измерения в CSS — это суффиксы у чисел (16px, 1.5rem, 50vw), которые говорят браузеру, от какой опорной величины считать размер. Они делятся на две группы. Абсолютные (px, а также cm, mm, in, pt, pc, Q) жестко привязаны к пикселю CSS. Относительные зависят от чего-то еще: em — от размера шрифта, rem — от шрифта корневого элемента, % — от родителя, vw/vh — от окна браузера, ch — от ширины символа.
Содержание
- Мини-словарь
- Сводная таблица: от чего считается каждая единица
- Минимальный пример: карточка на rem, em, ch и clamp()
- Пиксели и физические единицы
- em и rem: шрифт родителя против шрифта корня
- Проценты: у каждого свойства своя опора
- vw, vh, vmin, vmax и мобильные dvh
- ch, lh и единицы контейнера
- clamp(), calc(), min() и max(): смешивание единиц
- Как выбрать единицу: алгоритм
- Если размер получился не тот
- Выводы
- Где применяется / связь с практикой
- FAQ
Короткий ответ, что когда брать: шрифты и отступы — в rem, внутренние отступы компонента — в em, ширины колонок — в %, размеры относительно экрана — в vw/vh/dvh, длину строки текста — в ch, тонкие рамки — в px, плавный шрифт — через clamp(). Ниже — от чего считается каждая единица, примеры с реальными значениями и типичные ошибки. Значения проверены в Chromium 149 (headless) 24.09.2026.
Мини-словарь
- Длина — число плюс единица:
24px,1.5em. Для нуля единицу можно не писать:margin: 0. - Опорная величина — то, от чего считается относительная единица: шрифт родителя, ширина контейнера, окно браузера.
- Вычисленное значение — итоговый размер, в который браузер переводит любые единицы. Его видно в DevTools на вкладке Computed или через
getComputedStyle().
Сводная таблица: от чего считается каждая единица
| Единица | От чего считается | Типичное применение | Подводный камень |
|---|---|---|---|
px |
Пиксель CSS (1/96 дюйма) | Рамки, тени, мелкие детали | Шрифт в px игнорирует размер шрифта из настроек браузера |
em |
В font-size — шрифт родителя, в остальных свойствах — свой шрифт |
Отступы кнопки, иконки рядом с текстом | Накапливается во вложенных элементах |
rem |
Шрифт корневого html (по умолчанию обычно 16px) |
Шрифты, отступы, сетка отступов | В @media считается от шрифта браузера, а не от html |
% |
У каждого свойства своя опора (обычно родитель) | Ширина колонок | padding-top: 10% считается от ширины, а не высоты |
vw, vh |
1% ширины / высоты окна | Полноэкранные блоки | 100vw шире страницы при видимой полосе прокрутки |
vmin, vmax |
1% меньшей / большей стороны окна | Элементы, одинаковые в портрете и альбоме | Редко нужны в обычной верстке |
dvh, svh, lvh |
Высота окна с учетом панелей мобильного браузера | Первый экран на телефоне | В старых браузерах нужен запасной vh |
ch |
Ширина символа «0» текущего шрифта | Максимальная длина строки | Зависит от шрифта |
cqi, cqw |
1% размера контейнера | Компоненты, которые живут в колонках разной ширины | Нужен container-type у предка |
Минимальный пример: карточка на rem, em, ch и clamp()
Сохраните как index.html и откройте в браузере:
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html { font-size: 100%; }
body { margin: 0; font-family: system-ui, sans-serif; line-height: 1.5; }
.page { max-width: 70rem; margin: 0 auto; padding: 0 1rem; }
.card { border: 1px solid #ccc; border-radius: 0.5rem; padding: 1.5em; }
.card h2 { font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem); margin: 0 0 0.5em; }
.card p { max-width: 60ch; margin: 0 0 1em; }
.btn { font-size: 0.875rem; padding: 0.5em 1em; }
</style>
</head>
<body>
<main class="page">
<article class="card">
<h2>Единицы измерения в CSS</h2>
<p>Абзац не шире 60 символов: такую строку удобно читать.</p>
<button class="btn">Подробнее</button>
</article>
</main>
</body>
</html>
Вычисленные значения при шрифте браузера 16px:
окно 375px: h2 24px, padding карточки 24px, кнопка: шрифт 14px, отступы 7px 14px
окно 1000px: h2 36px, padding карточки 24px, кнопка: шрифт 14px, отступы 7px 14px
окно 1600px: h2 40px, padding карточки 24px, кнопка: шрифт 14px, отступы 7px 14px
Что здесь происходит. Рамка 1px не должна масштабироваться — это деталь, поэтому пиксели. padding: 1.5em у карточки — это 1.5 x 16 = 24px, а у кнопки 0.5em 1em считается от ее собственного шрифта 14px, поэтому 7px и 14px: отступы растут вместе с текстом кнопки. Заголовок меняется с шириной окна, но не выходит за 24-40px — это работа clamp(), разобранная ниже. 60ch ограничивает абзац примерно 60 символами; в пикселях это зависит от шрифта (для system-ui 16px в этом прогоне — около 605px).
Пиксели и физические единицы
px в CSS — это не физическая точка экрана, а условный пиксель CSS. На экране с плотностью 2x (devicePixelRatio = 2) один пиксель CSS рисуется квадратом 2×2 физических точки. Дробные значения вроде 0.5px допустимы, при отрисовке браузер их округляет или сглаживает.
Физические единицы в CSS пересчитываются через пиксели по фиксированному соотношению:
1in = 96px 1cm ≈ 37.8px 1mm ≈ 3.78px
1pt = 1/72in ≈ 1.33px 1pc = 12pt = 16px 1Q = 0.25mm ≈ 0.94px
Поэтому на мониторе 1cm не обязан совпасть с сантиметром на линейке. Сантиметры и пункты имеют смысл в стилях для печати (@media print), для экрана они ничего не дают по сравнению с px.
em и rem: шрифт родителя против шрифта корня
em ведет себя по-разному в зависимости от свойства. В font-size 1em равен шрифту родителя. Во всех остальных свойствах (padding, margin, width) 1em равен шрифту самого элемента. Проверка: у родителя 20px, у потомка font-size: 1.5em; padding: 1em — шрифт потомка 30px, и отступ тоже 30px, а не 20px.
Из-за первого правила em накапливается во вложенных элементах. Неверно:
body { font-size: 16px; }
.menu li { font-size: 1.2em; }
При трех уровнях вложенных списков размеры получаются такими:
уровень 1: 19.2px уровень 2: 23.04px уровень 3: 27.648px
Каждый li умножает шрифт родителя на 1.2. Исправление — rem, он всегда считается от корня:
.menu li { font-size: 1.2rem; }
уровень 1: 19.2px уровень 2: 19.2px уровень 3: 19.2px
Почему шрифты лучше задавать в rem, а не в px: если пользователь увеличил базовый шрифт в настройках браузера, все размеры в rem вырастут пропорционально, а font-size в px останется прежним. Масштаб страницы (Ctrl и +) увеличивает размеры в px, em, rem и %, но не размеры, заданные только в vw/vh (почему — в разделе про clamp()), а настройку шрифта уважают только rem, em и %. По той же причине не стоит задавать html { font-size: 16px; } — лучше 100% или вообще ничего.
Отдельный случай — медиазапросы. Внутри @media единицы em и rem считаются от начального шрифта браузера, а не от html. Проверка при html { font-size: 62.5%; } (10px) и окне 500px: 40rem в разметке дает 400px, но @media (min-width: 40em) не срабатывает, потому что для него 40em = 640px.
Проценты: у каждого свойства своя опора
% — единица без общей опоры, у каждого свойства она своя:
width,left,right— ширина содержащего блока (обычно родителя).height— высота родителя, но только если она задана явно. Приheight: autoу родителяheight: 50%у потомка не сработает.paddingиmargin— ширина родителя, даже для верхнего и нижнего отступа. В блоке 500×200padding-top: 10%дает 50px, аheight: 50%— 100px.font-size— шрифт родителя, какem.transform: translate(50%)— размер самого элемента.
С line-height есть ловушка наследования. Проценты вычисляются один раз и наследуются уже в пикселях, а число без единицы наследуется как коэффициент:
.a { font-size: 20px; line-height: 150%; } /* потомок с шрифтом 40px получит 30px */
.b { font-size: 20px; line-height: 1.5; } /* потомок с шрифтом 40px получит 60px */
В первом случае крупный текст потомка налезает строками друг на друга, поэтому для line-height обычно пишут число без единицы. Подробно о процентах в width, height и box-sizing — в статье о ширине и высоте блока в CSS.
vw, vh, vmin, vmax и мобильные dvh
1vw — 1% ширины окна браузера, 1vh — 1% высоты. vmin берет меньшую сторону, vmax — большую. В окне 1000×800 10vmin = 80px (от высоты), 10vmax = 100px (от ширины). Если повернуть телефон, опорная сторона поменяется.
Типичная ошибка — width: 100vw для блока на всю ширину. В vw входит полоса прокрутки, если она занимает место (обычно в Windows и Linux, в macOS — при соответствующей настройке). Проверка в окне 500px с полосой 15px:
100vw = 500px, ширина страницы = 485px -> появляется горизонтальная прокрутка
100% = 485px -> прокрутки нет
Исправление — width: 100% у блока внутри страницы без ограничивающего родителя. В Chrome 145 и новее есть и второй путь: если у корня задано html { scrollbar-gutter: stable; } или overflow-y: scroll, 100vw уже вычитает ширину полосы прокрутки; в браузерах без этой доработки vw по-прежнему ее включает.
Вторая ловушка — 100vh на телефонах. Мобильный браузер прячет и показывает адресную строку, и vh равен высоте окна при скрытых панелях, поэтому низ блока уходит под панель. Для этого есть отдельные единицы: svh — высота при показанных панелях (маленькое окно), lvh — при скрытых (большое), dvh — текущая, меняется на ходу. Надежный вариант с запасом для старых браузеров:
.hero {
min-height: 100vh; /* запасной вариант */
min-height: 100dvh; /* браузер, который понимает dvh, возьмет это значение */
}
ch, lh и единицы контейнера
ch — ширина символа «0» в текущем шрифте. max-width: 60ch ограничивает абзац примерно 60-70 символами обычного текста: для моноширинного шрифта это точное число символов, для пропорционального — приблизительное, потому что буквы разной ширины.
lh — высота строки элемента: при font-size: 16px и line-height: 1.5 значение 2lh = 48px. Удобно для блока ровно на две или три строки текста.
cqi и cqw — 1% ширины контейнера, а не окна. Они работают, только если у предка указан container-type:
.column { container-type: inline-size; }
.column p { font-size: 5cqi; } /* в колонке шириной 400px шрифт будет 20px */
Это решает задачу, которую vw решить не может: одна и та же карточка в узкой боковой колонке и в широкой основной меняет размеры по своей колонке, а не по экрану.
clamp(), calc(), min() и max(): смешивание единиц
Функции позволяют сложить разные единицы и поставить границы. calc(1rem + 2vw) складывает шрифт и долю окна. min(100%, 40rem) берет меньшее, max() — большее. clamp(MIN, ЖЕЛАЕМОЕ, MAX) держит значение в коридоре.
Расчет для заголовка из первого примера, clamp(1.5rem, 1rem + 2vw, 2.5rem):
| Ширина окна | 1rem + 2vw | Итог |
|---|---|---|
| 375px | 16 + 7.5 = 23.5px | 24px (сработал минимум 1.5rem) |
| 1000px | 16 + 20 = 36px | 36px |
| 1600px | 16 + 32 = 48px | 40px (сработал максимум 2.5rem) |
Зачем в середине rem, а не просто 5vw. Шрифт только на vw не растет при масштабировании страницы: при зуме CSS-ширина окна уменьшается ровно во столько раз, во сколько растет пиксель CSS, и видимый размер текста остается прежним. Для доступности это проблема: пользователь не может увеличить такой текст зумом. Слагаемое в rem сохраняет реакцию на зум и на настройку шрифта. Раньше ту же задачу решали через calc() и несколько медиазапросов; clamp() делает это одной строкой.
Внутри calc() у нуля единица обязательна: calc(0 + 10px) браузер отбросит как ошибку, calc(0px + 10px) сработает.
Как выбрать единицу: алгоритм
- Размер должен реагировать на настройку шрифта пользователя? Шрифт, отступы, высота кнопки —
rem. - Отступ должен расти вместе с текстом конкретного компонента?
em. - Размер зависит от места, где стоит элемент? Доля родителя —
%, доля колонки —cqi. - Размер зависит от экрана?
vw,dvh, лучше внутриclamp()с границами. - Это длина строки текста?
ch. - Это деталь, которая не должна масштабироваться (рамка, тень, линия)?
px.
Если размер получился не тот
- Текст растет с каждым уровнем вложенности —
emвfont-sizeнакапливается. Замените наrem. - Появилась горизонтальная прокрутка — где-то
width: 100vw. Замените на100%. - Блок с
height: 50%имеет нулевую высоту — у родителя высотаauto. Задайте высоту родителю или используйте flex/grid. - Низ первого экрана на телефоне скрыт —
100vh. Используйте100dvhили100svhс запаснымvh. - Медиазапрос срабатывает не на той ширине —
em/remв@mediaсчитаются от шрифта браузера, а не отhtml. - Увеличение шрифта в настройках браузера ничего не меняет — шрифты заданы в
px.
Проверять лучше не глазами: в DevTools выберите элемент и откройте вкладку Computed — там видно, во сколько пикселей превратилась каждая единица.
Выводы
- Абсолютная единица для экрана по сути одна —
px;cm,ptи остальные пересчитываются через нее и нужны в основном для печати. rem— основа для шрифтов и отступов: не накапливается и уважает настройку шрифта пользователя.emудобен для отступов внутри компонента, но вfont-sizeнакапливается во вложенных элементах.- У
%нет общей опоры:padding-topв процентах считается от ширины,heightв процентах требует явной высоты родителя. 100vwломается на полосе прокрутки,100vh— на мобильных панелях; есть100%иdvh, а плавный шрифт надежнее собрать черезclamp()сrem.
Где применяется / связь с практикой
Освойте тему на практике
Выбор единиц — это ежедневная работа верстальщика: от него зависит, развалится ли макет на телефоне, будет ли текст читаемым на широком мониторе и учтет ли страница настройки пользователя. На курсе «HTML/CSS» адаптивная верстка разбирается на практических проектах с ревью. Послушать отдельные темы бесплатно можно на открытых уроках Otus.
FAQ
Сколько пикселей в 1rem?
По умолчанию в браузерах 16px, но пользователь может поменять базовый шрифт в настройках, и тогда 1rem изменится. Поэтому на точное «1rem = 16px» в расчетах полагаться нельзя.
Что такое fr — это тоже единица длины?
fr — доля свободного места в CSS Grid, она работает только в grid-template-columns, grid-template-rows и похожих свойствах. Записать width: 1fr нельзя, браузер отбросит такое объявление.
Можно ли смешивать единицы в одном значении?
Да, через calc(), min(), max() и clamp(): например, calc(100% - 2rem) — ширина родителя минус два шрифта корня.



