290 lines
17 KiB
Markdown
290 lines
17 KiB
Markdown
# Единицы измерения: "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`, но они давно отправились на свалку истории.
|
||
|
||
Вот, если интересно, их значения:
|
||
<ul>
|
||
<li>`1mm` (мм) = `3.8px`</li>
|
||
<li>`1cm` (см) = `38px`</li>
|
||
<li>`1pt` (типографский пункт) = `4/3 px`</li>
|
||
<li>`1pc` (типографская пика) = `16px`</li>
|
||
</ul>
|
||
Так как браузер пересчитывает эти значения в пиксели, то смысла в их употреблении нет.
|
||
[/warn]
|
||
|
||
[smart header="Почему сантиметре `cm` содержится ровно 38 пикселей?"]
|
||
В реальной жизни сантиметр -- это такой отрезок, эталон длины. А [пиксель](http://ru.wikipedia.org/wiki/%D0%9F%D0%B8%D0%BA%D1%81%D0%B5%D0%BB%D1%8C) может быть разным, в зависимости от экрана.
|
||
|
||
Но в формулах выше под пикселем понимается "сферический пиксель в вакууме", точка на "стандартизованном экране", характеристики которого описаны в [спецификации](http://www.w3.org/TR/CSS2/syndata.html#length-units).
|
||
|
||
Поэтому ни о каком соответствии `cm` реальному сантиметру здесь нет и речи. Полностью синтетическая и ненужная единица измерения.
|
||
[/smart]
|
||
|
||
|
||
## Относительно шрифта: em
|
||
|
||
`1em` -- текущий размер шрифта.
|
||
|
||
Можно брать любые пропорции от текущего шрифта: `2em`, `0.5em` и т.п.
|
||
|
||
**Размеры в `em` -- *относительные*, они определяются по текущему контексту.**
|
||
|
||
Например, давайте сравним `px` с `em` на таком примере:
|
||
|
||
```html
|
||
<!--+ autorun height=80 -->
|
||
<div style="font-size:24px">
|
||
Страусы
|
||
<div style="font-size:24px">Живут также в Африке</div>
|
||
</div>
|
||
```
|
||
|
||
`24` пикселей -- и в Африке `24` пикселей, поэтому две строчки выше одинаковы.
|
||
|
||
А вот аналогичный пример с `em` вместо `px`:
|
||
|
||
```html
|
||
<!--+ 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](http://www.w3.org/TR/css3-values/#ex-unit) и [ch](http://www.w3.org/TR/css3-values/#ch-unit) ), которые означают размер в зависимости от таких характеристик шрифта как размер символа `"x"` и размер символа `"0"`.
|
||
|
||
Эти размеры присутствуют всегда, даже если по коду этих символов в шрифте находятся другие значения, а не именно буква `"x"` и ноль `"0"`.
|
||
|
||
Эти единицы используются чрезвычайно редко, так как "размер шрифта" `em` обычно вполне подходит.
|
||
[/smart]
|
||
|
||
## Проценты %
|
||
|
||
Проценты `%`, как и `em` -- относительные единицы.
|
||
|
||
Вот пример с `%`, он выглядит в точности так же, как с `em`:
|
||
|
||
```html
|
||
<!--+ autorun height=120 -->
|
||
<div style="font-size:150%">
|
||
Страусы
|
||
<div style="font-size:150%">Живут также в Африке</div>
|
||
</div>
|
||
```
|
||
|
||
Когда мы говорим "процент", то возникает вопрос -- "Процент от чего?"
|
||
|
||
**Как правило, процент будет от значения свойства родителя с тем же названием, но не всегда.**
|
||
|
||
Это очень важная особенность процентов, про которую, увы, часто забывают.
|
||
|
||
Отличный источник информации по этой теме -- стандарт, [Visual formatting model details](http://www.w3.org/TR/CSS2/visudet.html).
|
||
|
||
Некоторые примеры:
|
||
<ul>
|
||
<li>При установке свойства `margin-left` в `%`, процент берётся от *ширины* родительского блока (а вовсе не от его `margin-left`!)</li>
|
||
<li>При установке свойства `line-height` в `%`, процент берётся от текущего *размера шрифта* (а вовсе не от текущего `line-height`!)</li>
|
||
<li>Для `width/height` при `position:fixed`, процент берётся от ширины/высоты *окна* (а не родителя и не документа).</li>
|
||
<li>Кроме того, иногда `%` требует соблюдения дополнительных условий, за примером -- обратитесь к статье [](/height-percent).</li>
|
||
<li>Детали по `line-height` и размеру шрифта вы также можете найти в статье [](/font-size-line-height).</li>
|
||
</ul>
|
||
|
||
## Микс px и em: rem
|
||
|
||
Итак, что у нас есть:
|
||
<ul>
|
||
<li>`px` -- абсолютные, чёткие, понятные, не зависящие ни от чего.</li>
|
||
<li>`em` -- относительно размера шрифта.</li>
|
||
<li>`%` -- относительно такого же свойства родителя (а может и не родителя, а может и не такого же -- см. оговорки выше).</li>
|
||
</ul>
|
||
|
||
Может быть, пора уже остановиться, может этого достаточно?
|
||
|
||
Э-э, нет! Не все вещи делаются удобно.
|
||
|
||
Вернёмся к теме шрифтов. Бывают задачи, когда мы хотим сделать на странице большие кнопки "Шрифт больше" и "Шрифт меньше". При нажатии на них будет срабатывать JavaScript, который будет увеличивать или уменьшать шрифт.
|
||
|
||
Вообще-то это можно сделать без JavaScript, в браузере обычно есть горячие клавиши для масштабирования вроде [key Ctrl++], но они работают слишком тупо -- берут и увеличивают всю страницу, вместе с изображениями и другими элементами, которые масштабировать как раз не надо. А надо увеличить, к примеру, только шрифт, потому что посетитель хочет комфортнее читать. И увеличенный шрифт по-новому обтечёт элементы страницы.
|
||
|
||
Какую единицу использовать для задания шрифтов? Лучше бы не `px`, ведь такие значения абслютны, если менять, то везде, вполне возможна ситуация, когда мы в одном правиле размер поменяли, а другое забыли.
|
||
|
||
Следующие кандидаты -- `em` и `%`.
|
||
|
||
Разницы между ними здесь нет, так как при задании `font-size` в процентах, эти проценты берутся от `font-size` родителя, то есть ведут себя так же, как и `em`.
|
||
|
||
Вроде бы, использовать можно, однако есть проблема.
|
||
|
||
Посмотрите на пример с вложенными `<li>`:
|
||
|
||
```html
|
||
<!--+ 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` для задания шрифтов внутри:
|
||
|
||
```html
|
||
<!--+ 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-. Для этих браузеров, которых становится всё меньше, есть два выхода:
|
||
<ol>
|
||
<li>Либо использовать `em` и правила, страхующие от вложенности, вроде:
|
||
|
||
```css
|
||
li { font-size: 0.8em }
|
||
li li { font-size: 0.8em }
|
||
li li li { font-size: 0.8em }
|
||
```
|
||
|
||
</li>
|
||
<li>Либо сделать два правила в стилях: первое указывает размер в `px` (для IE8-), а второе -- в `rem` (переопределит первое в современных браузерах) и отключить маштабирование шрифтов для IE8-. Это проще.</li>
|
||
</ol>
|
||
[/warn]
|
||
|
||
## Относительно экрана: vw, vh, vmin, vmax
|
||
|
||
Во всех современных браузерах, исключая IE8-, поддерживаются новые единицы из черновика стандарта [CSS Values and Units 3](http://dev.w3.org/csswg/css3-values/):
|
||
|
||
<ul>
|
||
<li>`vw` -- 1% ширины окна</li>
|
||
<li>`vh` -- 1% высоты окна</li>
|
||
<li>`vmin` -- наименьшее из (`vw`, `vh`), в IE9 обозначается `vm`</li>
|
||
<li>`vmax` -- наибольшее из (`vw`, `vh`)</li>
|
||
</ul>
|
||
|
||
**Эти значения были созданы, в первую очередь, для поддержки мобильных устройств.**
|
||
|
||
Их основное преимущество -- в том, что любые размеры, которые в них заданы, автоматически масштабируются при изменении размеров окна.
|
||
|
||
Ниже написан текст с размером `5vh`:
|
||
|
||
<p style="font-size:5vh">Страусы кусачими не бывают.</p>
|
||
|
||
**Вы сможете легко увидеть, как работает `vh`, если поменяете размер окна браузера. Текст будет расти/уменьшаться.**
|
||
|
||
## Итого
|
||
|
||
Мы рассмотрели единицы измерения:
|
||
|
||
<ul>
|
||
<li>`px` -- абсолютные пиксели, к которым привязаны и потому не нужны `mm`, `cm`, `pt` и `pc`. Используется для максимально конкретного и точного задания размеров.</li>
|
||
<li>`em` -- задаёт размер относительно шрифта родителя, можно относительно конкретных символов: `"x"`(`ex`) и `"0"`(`ch`), используется там, где нужно упростить масштабирование компоненты.</li>
|
||
<li>`rem` -- задаёт размер относительно шрифта `<html>`, используется для удобства глобального масштабирования: элементы которые планируется масштабировать, задаются в `rem`, а JS меняет шрифт у `<html>`.</li>
|
||
<li>`%` -- относительно такого же свойства родителя (как правило, но не всегда), используется для ширин, высот и так далее, без него никуда, но надо знать, относительно чего он считает проценты.</li>
|
||
<li>`vw`, `vh`, `vmin`, `vmax` -- относительно размера экрана.</li>
|
||
</ul>
|
||
|
||
Здесь я постарался разобрать их применение и преимущества для решения конкретных задач, но вы, конечно, сможете использовать их для других ситуаций.
|