Единицы размеров в CSS
В CSS существует множество единиц измерения. Обычно мы используем единицы размеров, но также есть единицы для углов — например, deg
и turn
, единицы времени — s
и ms
, единицы плотности экрана — например, dpi
и dppx
и другие.
Здесь будут рассматриваться только единицы размеров, которыми мы пользуемся чаще всего. Подробное описание можно найти в спецификации W3C Distance Units: the <length> type.
Общим для всех единиц длины будет то, что для значения 0
, единицы можно не указывать: height: 0px
и height: 0
будут работать одинаково, так что единицы измерения можно отбросить. Это позволяет немного быстрее писать код и считывать значения свойств.
Абсолютные единицы измерения
cm |
сантиметр | 1cm = 96px/2.54 ≈ 37,795px |
mm |
миллиметр | 1mm = 1/10 от 1cm |
q |
четверь миллиметра | 1q = 1/40 от 1cm = 0.25mm ≈ 0.945px |
in |
дюйм | 1in = 2.54cm = 96px |
pc |
пика | 1pc = 1/6 от 1in |
pt |
пункт, точка | 1pt = 1/72 от 1in |
px |
пиксель | 1px = 1/96 от 1in, 0.75 от pt |
Абсолютные единицы относительны друг для друга (соотношения в последней колонке), но все они привязаны к конкретным величинам.
Для печатных устройств сантиметры, миллиметры и дюймы должны быть равны своим обычным значениям, но для экранов это будет не так:
Я попыталась разными способами получить полоску длиной 10 сантиметров. Все полоски равны друг другу, но ни одна не равна 10 сантиметрам, если приложить линейку к экрану. Проверила на двух мониторах: на одном они короче, на другом — длиннее.
На веб-страницах физические единицы измерения вроде cm
, mm
и in
не будут работать как ожидается, потому что главная экранная единица измерения — пиксель.
Что такое пиксель и какого он размера? Чем отличаются пиксели px
от точек pt
? Почему у них такие странные размеры в 1/96 дюйма и 1/72 дюйма соответственно? Как были выбраны эти значения и почему этих единиц измерения две? Попытка разобраться с мелкой точкой на экране вызывает множество вопросов и требует погружения в историю. Я попыталась выяснить как всё было, и вот что узнала.
Когда появились первые программы для предпечатной подготовки, нужно было как-то соотнести размер элементов на экране с тем, чтоб будет напечатано на бумаге. Тогда оказалось, что один дюйм (inch) на экране соответствует 72 точкам. Это соотношение зафиксировано в pt
, pt
— это 1/72 дюйма. Изначально это была типографская единица измерения, и её значения менялись со временем, но с появлением компьютерных программ для полиграфии значение pt
пришлось стандартизировать.
С развитием технологий стало возможно делать экраны с большим разрешением, и Microsoft предложила отображать 96 точек на дюйм, что было зафиксировано в px
, то есть пиксель — это 1/96 дюйма. Это позволило увеличить чёткость мелкого текста, потому что для отображения символа теперь можно было использовать больше точек.
Размер px
составляет 0.75 от pt
. По сути, pt
— это более крупный пиксель.
Позже появились ретиновые дисплеи с повышенной плотностью пикселей, и тогда CSS-пиксели, которые мы используем, перестали соответствовать физическим пикселям экрана, теперь это виртуальная единица, размер которой определяется устройством вывода. Для нас это не играет особой роли кроме как при работе с изображениями, когда для ретины нужно подготовить дополнительный набор картинок. Все размеры, заданные в пикселях, будут корректно отображены на экране вне зависимости от того, сколько физических пикселей для этого потребуется.
На сегодняшний момент соотношение физических единиц к точкам экрана утратило прежний смысл, но осталось зафиксированым в спецификации для сохранения обратной совместимости и упрощения конвертации одних единиц в другие.
При этом важно помнить, что раз CSS-пиксели уже не соответствуют физическим точкам экрана, сантиметры и дюймы при выводе на экран тоже не будут не соответствовать своим реальным размерам, об этом есть и в спецификации:
If the anchor unit is the pixel unit, the physical units might not match their physical measurements. Alternatively if the anchor unit is a physical unit, the pixel unit might not map to a whole number of device pixels.
То есть, если использовать дюймы для вёрстки веб-страниц, один дюйм всегда будет равен 96 пикселям, но никогда — реальной физической единице:
Таким образом, главное в абсолютных единицах — контекст использования:
- для вывода на печать экранные пиксели должны быть приведены к физическими единицами, следовательно, для подготовки документов к печати лучше использовать их;
- для вывода на экран дюймы и сантиметры должны быть приведены к пикселям, следовательно, для веб-разработки лучше сразу использовать пиксели.
Пока копалась в истории единиц измерения, выяснилось, что во внутреннем коде Gecko когда-то была поддержка километров, удалили в 2009-м:
Из физических единиц ещё может представлять интерес q
: это относительно новая единица, и она поддерживается не всеми браузерами. q
— это 0.25mm
. Как и другие физические единицы, больше имеет смысл для печати, но также можно попытаться использовать её для уменьшения размера кода: q
— это примерно 0.945px
, то есть в некоторых случаях вполне можно использовать её вместо пикселей, получается один символ (q
) вместо двух (px
).
Пример такого использования я подсмотрела в этом демо. Открывайте осторожно, может повиснуть браузер. Попытка посмотреть стили в веб-инспекторе вешает его почти гарантированно, поэтому лучше посмотрите исходный код страницы. Скриншот:
Чистое безумие, конечно. Картина воспроизведена с помощью box-shadow
, и мне кажется, тему рисования на CSS на этом можно закрывать.
Вес стилей демо — 4.5Mb, а если бы там вместо q
были пиксели, стили весили бы на 300Kb больше.
Относительные единицы измерения
Относительные единицы измерения вычисляются на основе каких-то других величин: размера шрифта или размера экрана, и могут динамически меняться вместе с ними.
Единицы измерения, привязанные к шрифту
em |
размер шрифта элемента |
ex |
высота x в нижнем регистре |
ch |
ширина 0 (ZERO, U+0030) |
rem |
размер шрифта корневого элемента |
em
Для font-size
это унаследованный размер шрифта, для остальных свойств — текущий размер шрифта, уже вычисленный для font-size
.
Чтобы увидеть это вживую, возьмем такой код:
Получилось вот что:
Розовая полоса — градиент высотой 1em
, чтобы было с чем сравнивать.
Оба блока имеют одинаковый размер шрифта, уменьшенный относительно родительского элемента в два раза (font-size: .5em;
). И как теперь указать толщину рамки равной размеру шрифта?
border-width: .5em
делает рамку в два раза тоньше, чем нужно. Это происходит потому, что родительский размер шрифта использует только font-size
, а border
получает вычисленное значение из font-size
.
Таким образом, если где-то не в font-size
нужно использовать текущий размер шрифта, не нужно копировать значение размера, достаточно указать 1em
. У правого блока рамка правильной толщины.
Ещё одно демо, для понимания как соотносятся em
и символы шрифта. Цветные полосы имеют высоту 1em
, поэтому видно, что 1em
примерно соответствует высоте символов с учётом заглавных букв и выносных элементов:
Размер em
нигде не зафиксирован, и вычисляется в момент использования на основе размера шрифта родителя. Например, если задать размер шрифта вот таким образом:
а потом вложить несколько дивов один в другой, размер шрифта каждого следующего дива будет меньше предыдущего:
Потому что 1em
— это текущий унаследованный размер шрифта, а .75em
— унаследованный шрифт, уменьшенный на четверть. Для каждого нового вложенного дива сначала наследуется уменьшенный шрифт родителя, а потом тоже уменьшается заданным образом.
Об этом нужно помнить, если вы захотите задавать в em
размеры переиспользуемых компонентов: при вкладывании элементов друг в друга вычисленное значение em
может оказаться не тем, что хотелось бы получить.
ex
ex
— это высота буквы x
в нижнем регистре. Если в шрифте нет подходящей метрики, и в нём нет такого символа, браузер попробует вычислить ex
самостоятельно. Если это по каким-то причинам невозможно, ex
считается равным .5em
.
В демо цветные полосы имеют высоту 1ex
, и для выбранных шрифтов 1ex
будет равен высоте маленькой x
:
Посмотрим, как на ex
влияет шрифт, и как ex
соотносится с em
.
В этом демо квадратикам в левой группе заданы размеры в 1em
, в правой — в 2ex
, так можно проверить равен ли ex
половине em
. Также каждому квадратику задан свой шрифт:
В отличие от em
, размер ex
будет меняться вместе со шрифтом, и во всех случаях 2ex
не равно 1em
, то есть на соотношение в .5
полагаться нельзя.
ex
точно также как и em
наследует размер шрифта родителя:
ch
ch
— ширина символа 0
. Для моноширинных шрифтов это точная ширина любого символа, для остальных — примерная ширина одного узкого символа. Если по каким-то причинам ширину невозможно вычислить, запасным значением будет .5em
.
Эрик Мейер предостерегает от попыток использовать ch
для задания ширины контейнера в символах, потому что это не работает как ожидается. В демо ниже ширина каждого блока с текстом задана вот таким образом:
Ширина блока будет верной только для моноширинных шрифтов (см. Courier
), в некоторых шрифтах будет работать и для цифр (Arial
, Comic Sans
), в остальных случаях нельзя рассчитывать, что 1ch
будет равен ширине символа:
Сопоставим 1em
, 2ex
и 2ch
:
Очевидно, что:
1ch
больше1ex
(ширина0
больше высотыx
);1ch
не равен половинеem
;- значение
ch
может меняться вместе со шрифтом.
rem
rem
— это root em
, размер шрифта корневого элемента, для веб-страницы это элемент html
. Размер шрифта по умолчанию — 16px
. Это значение не зафиксировано в спецификации, но используется всеми браузерами. Про историю вопроса можно почитать в рассылке W3C.
Если пользователь в настройках браузера задаст другое значение, оно переопределит размер шрифта корневого элемента. То есть если нужно сделать интерфейс, который будет масштабироваться под размер шрифта, выбранный пользователем, в качестве единицы измерения удобно использовать именно rem
.
Важно понимать, что размер rem
можно переопределить только для элемента html
. Например, возьмем такие стили:
Если rem
можно было бы переопределять в любом месте, текст бы увеличился, но этого не произошло:
Высота цветной полосы 24px
, чтобы было с чем сравнивать.
Если переопределить размер шрифта для элемента html
, всё сработает:
В отличие от em
, rem
всегда содержит размер шрифта только корневого элемента, поэтому вложенность ни на что не влияет:
Это позволяет делать компоненты, размеры которых привязаны к базовому размеру шрифта, но не зависят от вложенности элементов друг в друга.
Единицы измерения, привязанные к размерам экрана
vw |
1% ширины вьюпорта |
vh |
1% высоты вьюпорта |
vmin |
1% от меньшего из vw и vh |
vmax |
1% от большего из vw и vh |
Эти единицы предназначены для создания элементов, размер которых должен зависеть от размера окна (вьюпорта).
100vh
— это высота вьюпорта, очень удобно для элементов, которые должны растягиваться на всю страницу. Вот пример простой галереи, где каждая картинка будет полностью занимать один экран независимо от размеров окна браузера:
Размеры картинок задаются вот таким образом:
Ширина вьюпорта — 100vw
. Это значение позволяет растянуть на ширину экрана любой элемент при любой вложенность.
Если задать элементу ширину 100%
, получится ширина родителя, который, скорее всего, занимает только часть экрана, а 100vw
позволяет растянуть именно на ширину окна браузера не обращая внимания на размеры родительских элементов.
Правда, тут есть проблема: 100vw
— это ширина всего окна вместе с полосой прокрутки, а доступная для контента ширина окна полосу прокрутки не включает, из-за чего при попытке задать элементам ширину вьюпорта появится горизонтальный скролл:
Если нет возможности изменить вёрстку, чтобы избежать использования 100vw
, можно задать overflow-x: hidden
ближайшему родителю, растянутому на ширину страницы:
Проблема с полосами прокрутки будет видна только в десктопных браузерах, потому что на мобильных скроллбар размещается поверх страницы и не занимает пространство.
Если вы верстаете на MacOS, и полосы прокрутки исчезают сами по себе, выберите в System Perefences/General опцию «Показывать всегда», это позволит верстать страницы сразу с учетом сколлбаров:
Используя vw
и vh
можно делать полностью резиновые элементы, которые будут сами подстраиваться под размер окна, например, так:
Лучше всего открыть это демо в отдельной вкладке и порастягивать окно браузера.
С помощью vmin
можно сделать элемент, который всегда будет целиком помещаться в экран, сохраняя пропорции:
Это демо тоже лучше смотреть в отдельной вкладке, попробуйте порастягивать окно по вертикали и по горизонтали.
В отличие от единиц, привязанных к шрифту, единицы вьюпорта не реагируют на масштабирование страницы. Откройте это демо и поизменяйте масштаб используя Ctrl+
/Ctrl-
. Текст, размер которого задан в rem
, будет увеличиваться и уменьшаться, текст с размером, заданным в vw
, останется неизменным.
Пример с единицами вьюпорта ведёт себя совершенно логично, потому что масштабирование не меняет размер окна. Об этой особенности нужно помнить, если вы захотите использовать единицы вьюпорта для задания размера текста — пользователь не сможет сделать такой текст покрупнее.
В качестве решения предлагается примешивать единицы вьюпорта к относительным единицам измерения, привязанным к размеру шрифта, например, так:
Вживую можно потестить здесь, пример взят из этой статьи. Больше про управление размером шрифта с помощью единиц вьюпорта можно почитать тут.
За дополнение про особенности масштабирования спасибо @bekharsky.
У единиц, привязанных к размерам вьюпорта, могут быть проблемы с поддержкой в IE включая 11-й, поэтому обязательно проверяйте код в действующем браузере.
В спецификации описано немного больше единиц измерения, например:
cap
— высота заглавной буквыlh
— высота строкиrlh
— высота строки корневого элемента
Но в данный момент они нигде не поддерживаются, поэтому в статье не рассматриваются.
Спасибо Илье Стрельцыну за полезные ссылки.
- Ссылки по теме:
- Distance Units: the <length> type
- CSS <length>
- Point (typography)
- platform-specific font size issues — Mailing lists, 15 Dec 1998
- Making pt a non-physical unit — Mailing lists, 6 Jan 2010
- [CSS21] Issue 149 - px vs. pt — Mailing lists, 16 Jun 2010
- em, px, pt, cm, in…
- What is the CSS ‘ch’ Unit?
- The Lengths of CSS
- CSS Length Explained
- The Myth of DPI
- CSS Units
- Font sizing with rem
- Новые и старые единицы измерения (краткий обзор)
- CSS Viewport Units: A Quick Start
- Fluid Typography
- Fun with Viewport Units
- Simple Little Use Case for `vmin`
- Метки:
- шрифты,
- единицы измерения,
- текст