Position

Свойство position определяет метод позиционирования элемента: в нормальном потоке, относительно себя, относительно предка, относительно viewport или с привязкой при скролле. Совместно с top, right, bottom, left и inset задаёт точное расположение.

Зачем нужно

Нормальный поток расставляет элементы последовательно. Но модальные окна, тултипы, фиксированные шапки, липкие меню — всё это требует вывода элемента из потока или привязки к определённой точке.

Где используется

  • Фиксированные header и footer
  • Модальные окна и попапы
  • Тултипы и выпадающие меню
  • Sticky-навигация
  • Абсолютно позиционированные иконки, бейджи

Предпосылки


static — по умолчанию

Элемент в нормальном потоке. Свойства top, right, bottom, left не работают.

.normal {
  position: static; /* По умолчанию */
  top: 20px; /* Игнорируется! */
}

relative — относительно себя

Элемент остаётся в потоке, но смещается относительно своей нормальной позиции:

.shifted {
  position: relative;
  top: 10px;    /* Сдвинуть вниз на 10px */
  left: 20px;   /* Сдвинуть вправо на 20px */
}

Ключевые особенности:

  • Элемент остаётся в потоке (занимает место)
  • Сдвиг визуальный — другие элементы не перестраиваются
  • Создаёт контекст позиционирования для absolute-потомков
  • Создаёт stacking context при наличии z-index
/* Типичное использование — контейнер для absolute */
.card {
  position: relative; /* Контекст для бейджа */
}
.card .badge {
  position: absolute;
  top: -8px;
  right: -8px;
}

absolute — относительно позиционированного предка

Элемент выходит из потока и позиционируется относительно ближайшего предка с position != static:

.container {
  position: relative; /* Контекст позиционирования */
  width: 400px;
  height: 300px;
}

.tooltip {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%); /* Центрирование */
}

/* Если нет позиционированного предка — относительно <html> */

Растяжение на весь контейнер

.overlay {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  /* Или короче: */
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}

Центрирование absolute-элемента

/* Способ 1: transform */
.centered {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

/* Способ 2: inset + margin auto */
.centered {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 200px;
  height: 100px;
}

fixed — относительно viewport

Элемент фиксирован относительно окна браузера, не скроллится:

/* Фиксированная шапка */
.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 60px;
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  z-index: 100;
}

/* Не забыть отступ для контента */
body {
  padding-top: 60px;
}

/* Кнопка «наверх» */
.back-to-top {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 99;
}

Внимание: fixed позиционируется относительно viewport, КРОМЕ случая, когда предок имеет transform, filter или will-change. Тогда предок становится containing block.


sticky — липкое позиционирование

Элемент ведёт себя как relative, пока не достигнет порога — потом как fixed:

/* Липкая навигация */
.nav {
  position: sticky;
  top: 0; /* «Прилипнет» к верху при скролле */
  background: white;
  z-index: 10;
}

/* Липкий sidebar */
.sidebar {
  position: sticky;
  top: 80px; /* Отступ от верха */
}

/* Липкие заголовки таблицы */
thead th {
  position: sticky;
  top: 0;
  background: #f8f9fa;
}

Требования для работы sticky:

  • Указан хотя бы один offset (top, bottom, left, right)
  • Родитель НЕ имеет overflow: hidden или overflow: auto
  • У элемента есть пространство для скролла в родителе

Offset-свойства: top, right, bottom, left

.box {
  position: absolute;
  top: 20px;      /* Отступ от верха */
  right: 10px;    /* Отступ от правого края */
  bottom: auto;   /* По умолчанию */
  left: auto;     /* По умолчанию */
}

inset — сокращённое свойство

/* inset: top right bottom left */
.overlay {
  position: absolute;
  inset: 0; /* = top: 0; right: 0; bottom: 0; left: 0; */
}

.padded {
  position: absolute;
  inset: 10px; /* Отступ 10px со всех сторон */
}

.custom {
  position: absolute;
  inset: 10px 20px 30px 40px; /* top right bottom left */
}

/* Логические свойства */
.logical {
  position: absolute;
  inset-block: 0;   /* top + bottom */
  inset-inline: 0;  /* left + right */
}

Stacking Context (контекст наложения)

Новый stacking context создаётся при:

  • position: relative/absolute/fixed/sticky + z-index != auto
  • position: fixed / sticky (всегда)
  • opacity < 1
  • transform != none
  • filter != none
  • will-change с определёнными значениями
  • isolation: isolate

Подробнее: z-index


Практические примеры

Модальное окно

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal {
  position: relative; /* Для кнопки закрытия */
  background: white;
  border-radius: 12px;
  padding: 32px;
  max-width: 500px;
  width: 90%;
}

.modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
}

Бейдж на аватарке

.avatar-container {
  position: relative;
  display: inline-block;
}
.avatar-container .badge {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 16px;
  height: 16px;
  background: #2ecc71;
  border: 2px solid white;
  border-radius: 50%;
}

Липкие заголовки секций

.section-heading {
  position: sticky;
  top: 0;
  background: #f8f9fa;
  padding: 12px 16px;
  border-bottom: 1px solid #dee2e6;
  z-index: 5;
}

Частые ошибки

  1. Absolute без positioned-предка — элемент позиционируется относительно viewport:

    /* ЗАБЫЛИ position: relative на родителе */
    .parent { /* position: static по умолчанию */ }
    .child { position: absolute; top: 0; } /* Улетит к viewport! */
    
  2. Sticky не работает из-за overflow — родитель с overflow: hidden/auto блокирует sticky:

    /* НЕ РАБОТАЕТ */
    .parent { overflow: hidden; }
    .child { position: sticky; top: 0; }
    
  3. Fixed-элемент внутри transformed-предкаfixed ведёт себя как absolute:

    .parent { transform: scale(1); }
    .child { position: fixed; /* Привязан к parent, не к viewport! */ }
    
  4. Нет z-index на fixed-элементах — перекрываются другим контентом

  5. top: 0 и bottom: 0 без height — элемент растягивается на весь контейнер (иногда нежелательно)

Практика

  • Создать фиксированную шапку с position: fixed и отступ для контента
  • Реализовать тултип с position: absolute и центрированием
  • Создать sticky-навигацию
  • Построить модальное окно с overlay
  • Расположить бейдж уведомлений на иконке через absolute

Связанные темы

  • z-index — управление порядком наложения
  • Display — поток документа
  • Margin и Padding — отступы и позиционирование

Ресурсы