Чем em, rem, %, vh, vw отличаются друг от друга?

JuniorCSS #css #units

Вопрос

Чем отличаются единицы измерения em, rem, %, vh, vw в CSS?

Короткий ответ

Все они относительные, но относительны к разным вещам: em — к размеру шрифта родителя (или своего элемента для не-font-size свойств), rem — к размеру шрифта корневого <html>, % — к размеру родителя (свой для каждого свойства), vh/vw — к высоте/ширине окна просмотра (viewport).

Подробный ответ

  • em — относительно font-size ближайшего родителя (для свойства font-size) или относительно собственного font-size элемента (для padding, margin, width и т.д.). Из-за этого em накапливается: если вложить элементы с font-size: 1.5em друг в друга, размер будет расти каскадно.
  • rem ("root em") — всегда относительно font-size элемента <html> (по умолчанию 16px), независимо от вложенности. Поэтому rem предсказуемее em и обычно предпочтительнее для отступов и размеров шрифта.
  • % — относительно соответствующего свойства родителя: width: 50% — половина ширины родителя, line-height: 150% — полтора размера шрифта самого элемента и т.д. Значение "родителя" зависит от конкретного CSS-свойства.
  • vh/vw — 1% от высоты/ширины viewport (видимой области окна браузера) соответственно. 100vh — это полная высота экрана, независимо от родительских контейнеров. Есть нюанс на мобильных браузерах: адресная строка может менять фактическую высоту (отсюда dvh/svh/lvh в современном CSS).

Пример

html { font-size: 16px; }

.parent {
  font-size: 20px;
}

.child {
  font-size: 1.5em;   /* 20px * 1.5 = 30px, зависит от родителя */
  padding: 1.5rem;     /* 16px * 1.5 = 24px, всегда от html */
  width: 50%;           /* половина ширины .parent */
}

.hero {
  height: 100vh;        /* вся высота экрана */
  width: 100vw;          /* вся ширина экрана */
}

Дополнительные вопросы

  • Почему вложенный em может привести к неожиданному "разрастанию" шрифта?
  • В чём разница между vh и новыми dvh/svh/lvh?
  • Когда стоит использовать %, а когда rem, для адаптивной вёрстки?