17 KiB
Единицы измерения: "px", "em", "rem", "%" и другие
В этом очерке я постараюсь не только рассказать о различных единицах измерения, но и построить общую картину -- что и когда выбирать.
[cut]
Абсолютные: px
Пиксель px
-- это самая базовая, абсолютная и окончательная единица измерения.
Количество пикселей задаётся в настроках [разрешения экрана](http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D0%BA%D0%B0), один px
-- это как раз один такой пиксель на экране. Все значения браузер в итоге пересчитает в пиксели.
Пиксели могут быть дробными, например размер можно задать в 16.5px
. Это совершенно нормально, браузер сам использует дробные пиксели для внутренних вычислений. К примеру, есть элемент шириной в 100px
, его нужно разделить на три части -- волей-неволей появляются 33.333...px
.
Для мобильных устройств, у которых много пикселей на экране, но сам экран маленький, чтобы обеспечить читаемость, браузер автоматически применяет масштабирование. При окончательном отображении дробные пиксели, конечно же, округляются и становятся целыми.
[compare] +Главное достоинство пикселя -- чёткость и понятность -Другие единицы измерения -- в некотором смысле "мощнее", они являются относительными и позволяют устанавливать соотношения между различными размерами [/compare]
[warn header="Давно на свалке: mm
, cm
, pt
, pc
"]
Существуют также "производные" от пикселя единицы измерения: mm
, cm
, pt
и pc
, но они давно отправились на свалку истории.
Вот, если интересно, их значения:
- `1mm` (мм) = `3.8px`
- `1cm` (см) = `38px`
- `1pt` (типографский пункт) = `4/3 px`
- `1pc` (типографская пика) = `16px`
[smart header="Почему сантиметре cm
содержится ровно 38 пикселей?"]
В реальной жизни сантиметр -- это такой отрезок, эталон длины. А пиксель может быть разным, в зависимости от экрана.
Но в формулах выше под пикселем понимается "сферический пиксель в вакууме", точка на "стандартизованном экране", характеристики которого описаны в спецификации.
Поэтому ни о каком соответствии cm
реальному сантиметру здесь нет и речи. Полностью синтетическая и ненужная единица измерения.
[/smart]
Относительно шрифта: em
1em
-- текущий размер шрифта.
Можно брать любые пропорции от текущего шрифта: 2em
, 0.5em
и т.п.
Размеры в em
-- относительные, они определяются по текущему контексту.
Например, давайте сравним px
с em
на таком примере:
<!--+ autorun height=80 -->
<div style="font-size:24px">
Страусы
<div style="font-size:24px">Живут также в Африке</div>
</div>
24
пикселей -- и в Африке 24
пикселей, поэтому две строчки выше одинаковы.
А вот аналогичный пример с em
вместо px
:
<!--+ autorun height=120 -->
<div style="font-size:1.5em">
Страусы
<div style="font-size:1.5em">Живут также в Африке</div>
</div>
Так как значение в em
высчитывается относительно текущего шрифта, то вторая строка в 1.5
раза больше, чем первая.
Выходит, задавая размеры в em
, мы задаём зависимость элементов от стиля родителя. Хочется увеличить или уменьшить всё вместе -- легко, просто поправим один стиль.
[smart header="Также относительно шрифта: ex
, ch
"]
В спецификации указаны также единицы ex и ch ), которые означают размер в зависимости от таких характеристик шрифта как размер символа "x"
и размер символа "0"
.
Эти размеры присутствуют всегда, даже если по коду этих символов в шрифте находятся другие значения, а не именно буква "x"
и ноль "0"
.
Эти единицы используются чрезвычайно редко, так как "размер шрифта" em
обычно вполне подходит.
[/smart]
Проценты %
Проценты %
, как и em
-- относительные единицы.
Вот пример с %
, он выглядит в точности так же, как с em
:
<!--+ autorun height=120 -->
<div style="font-size:150%">
Страусы
<div style="font-size:150%">Живут также в Африке</div>
</div>
Когда мы говорим "процент", то возникает вопрос -- "Процент от чего?"
Как правило, процент будет от значения свойства родителя с тем же названием, но не всегда.
Это очень важная особенность процентов, про которую, увы, часто забывают.
Отличный источник информации по этой теме -- стандарт, Visual formatting model details.
Некоторые примеры:
- При установке свойства `margin-left` в `%`, процент берётся от *ширины* родительского блока (а вовсе не от его `margin-left`!)
- При установке свойства `line-height` в `%`, процент берётся от текущего *размера шрифта* (а вовсе не от текущего `line-height`!)
- Для `width/height` при `position:fixed`, процент берётся от ширины/высоты *окна* (а не родителя и не документа).
- Кроме того, иногда `%` требует соблюдения дополнительных условий, за примером -- обратитесь к статье [](/height-percent).
- Детали по `line-height` и размеру шрифта вы также можете найти в статье [](/font-size-line-height).
Микс px и em: rem
Итак, что у нас есть:
- `px` -- абсолютные, чёткие, понятные, не зависящие ни от чего.
- `em` -- относительно размера шрифта.
- `%` -- относительно такого же свойства родителя (а может и не родителя, а может и не такого же -- см. оговорки выше).
Может быть, пора уже остановиться, может этого достаточно?
Э-э, нет! Не все вещи делаются удобно.
Вернёмся к теме шрифтов. Бывают задачи, когда мы хотим сделать на странице большие кнопки "Шрифт больше" и "Шрифт меньше". При нажатии на них будет срабатывать JavaScript, который будет увеличивать или уменьшать шрифт.
Вообще-то это можно сделать без JavaScript, в браузере обычно есть горячие клавиши для масштабирования вроде [key Ctrl++], но они работают слишком тупо -- берут и увеличивают всю страницу, вместе с изображениями и другими элементами, которые масштабировать как раз не надо. А надо увеличить, к примеру, только шрифт, потому что посетитель хочет комфортнее читать. И увеличенный шрифт по-новому обтечёт элементы страницы.
Какую единицу использовать для задания шрифтов? Лучше бы не px
, ведь такие значения абслютны, если менять, то везде, вполне возможна ситуация, когда мы в одном правиле размер поменяли, а другое забыли.
Следующие кандидаты -- em
и %
.
Разницы между ними здесь нет, так как при задании font-size
в процентах, эти проценты берутся от font-size
родителя, то есть ведут себя так же, как и em
.
Вроде бы, использовать можно, однако есть проблема.
Посмотрите на пример с вложенными <li>
:
<!--+ run autorun -->
<style>
li {
font-size: 0.8em;
}
</style>
<ul>
<li>Собака
<ul>
<li>бывает
<ul>
<li>кусачей
<ul>
<li>только
<ul>
<li>от жизни
<ul>
<li>собачей</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Проблема очевидна. Хотели, как лучше, а получилось... Мелковато. Каждый <li>
получил размер шрифта 0.8
от внешнего, это не совсем то, чего мы бы здесь хотели.
Время появиться единице rem
, которая, можно сказать, придумана для таких случаев!
Единица rem
задаёт размер относительно размера шрифта элемента <html>
.
Как правило, браузеры ставят этому элементу некоторый "разумный" (reasonable) размер по-умолчанию, который мы, конечно, можем переопределить и использовать rem
для задания шрифтов внутри:
<!--+ run height=400 autorun -->
<style>
*!*
html {
font-size: 14px;
}
li {
font-size: 0.8rem;
}
*/!*
</style>
<div><button id="up">Кликните, чтобы увеличить размер шрифта</button></div>
<img src="https://js.cx/clipart/angry_dog.png">
<ul>
<li>Собака
<ul>
<li>бывает
<ul>
<li>кусачей
<ul>
<li>только
<ul>
<li>от жизни
<ul>
<li>собачей</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<script>
var html = document.documentElement;
up.onclick = function() {
// при помощи JS увеличить размер шрифта html на 2px
html.style.fontSize = parseInt(getComputedStyle(html, '').fontSize) + 2 + 'px';
};
</script>
Получилось удобное масштабирование для шрифтов, не влияющее на другие элементы.
Можно воспринимать rem
как остановку посередине между em
и px
, потому что элементы в rem
не зависят друг от друга и от контекста -- и этим похожи на px
, а с другой стороны они все заданы относительно размера шрифта <html>
.
[warn header="Не поддерживается в IE8-"]
Единица rem
не поддерживается в IE8-. Для этих браузеров, которых становится всё меньше, есть два выхода:
- Либо использовать `em` и правила, страхующие от вложенности, вроде:
li { font-size: 0.8em } li li { font-size: 0.8em } li li li { font-size: 0.8em }
- Либо сделать два правила в стилях: первое указывает размер в `px` (для IE8-), а второе -- в `rem` (переопределит первое в современных браузерах) и отключить маштабирование шрифтов для IE8-. Это проще.
Относительно экрана: vw, vh, vmin, vmax
Во всех современных браузерах, исключая IE8-, поддерживаются новые единицы из черновика стандарта CSS Values and Units 3:
- `vw` -- 1% ширины окна
- `vh` -- 1% высоты окна
- `vmin` -- наименьшее из (`vw`, `vh`), в IE9 обозначается `vm`
- `vmax` -- наибольшее из (`vw`, `vh`)
Эти значения были созданы, в первую очередь, для поддержки мобильных устройств.
Их основное преимущество -- в том, что любые размеры, которые в них заданы, автоматически масштабируются при изменении размеров окна.
Ниже написан текст с размером 5vh
:
Страусы кусачими не бывают.
Вы сможете легко увидеть, как работает vh
, если поменяете размер окна браузера. Текст будет расти/уменьшаться.
Итого
Мы рассмотрели единицы измерения:
- `px` -- абсолютные пиксели, к которым привязаны и потому не нужны `mm`, `cm`, `pt` и `pc`. Используется для максимально конкретного и точного задания размеров.
- `em` -- задаёт размер относительно шрифта родителя, можно относительно конкретных символов: `"x"`(`ex`) и `"0"`(`ch`), используется там, где нужно упростить масштабирование компоненты.
- `rem` -- задаёт размер относительно шрифта `<html>`, используется для удобства глобального масштабирования: элементы которые планируется масштабировать, задаются в `rem`, а JS меняет шрифт у `<html>`.
- `%` -- относительно такого же свойства родителя (как правило, но не всегда), используется для ширин, высот и так далее, без него никуда, но надо знать, относительно чего он считает проценты.
- `vw`, `vh`, `vmin`, `vmax` -- относительно размера экрана.
Здесь я постарался разобрать их применение и преимущества для решения конкретных задач, но вы, конечно, сможете использовать их для других ситуаций.