</> Praktum

Главная / CSS / CSS position

Урок · CSS

position: точное расположение элемента

Редакция PraktumОбновлено 16 минут на урок с практикойУровень: новичок

Свойство position задаёт способ позиционирования элемента: остаётся ли он в обычном потоке, от чего считаются его координаты top, right, bottom, left и прокручивается ли он вместе со страницей. Значений пять: static, relative, absolute, fixed и sticky.

Коротко
  • static — по умолчанию: координаты не действуют.
  • relative оставляет элемент в потоке и даёт точку отсчёта для абсолютных детей.
  • absolute вынимает элемент из потока и привязывает к ближайшему позиционированному предку.
  • fixed держится за окно браузера, sticky прилипает при прокрутке.
  • Сетку страницы строят Flexbox и Grid, а position — для бейджей, всплывашек и липких панелей.

Зачем этот урок сейчас

Бейдж «Новое» в углу карточки, крестик закрытия в модальном окне, шапка, которая едет за прокруткой, подсказка над кнопкой — всё это position. Без понимания, от чего считаются координаты, такие элементы «улетают» в угол окна, а z-index в 99999 ничего не решает.

Минимальный пример: бейдж в углу карточки

.card {
  position: relative;
}
.card .badge {
  position: absolute;
  top: 12px;
  right: 12px;
}
<article class="card">
  <span class="badge">Новое</span>
  <h3>Урок про Grid</h3>
</article>

Карточке достаточно position: relative без координат: она остаётся на месте, но становится точкой отсчёта. Бейдж с absolute вынут из потока и отсчитывает 12px от верхнего и правого края карточки, а не окна.

Пять значений position

Как ведёт себя каждое значение
ЗначениеВ потоке?От чего top/leftПри прокрутке
staticДаКоординаты игнорируютсяЕдет со страницей
relativeДа, место сохраняетсяОт своего обычного местаЕдет со страницей
absoluteНетОт ближайшего позиционированного предкаЕдет вместе с предком
fixedНетОт окна браузераСтоит на месте
stickyДаОт края области прокруткиЕдет, потом прилипает

relative: сдвиг без потери места

С position: relative элемент остаётся в потоке: соседи видят его на прежнем месте. top: 10px сдвигает только картинку вниз, а пустое место остаётся там, где элемент стоял. Поэтому relative редко используют для сдвига — чаще как «якорь» для абсолютных детей и чтобы у элемента заработал z-index.

absolute: от чего считаются координаты

Абсолютный элемент ищет ближайшего предка, у которого position не static: relative, absolute, fixed или sticky. Это его контейнер. Если такого предка нет, координаты считаются от начального контейнера — фактически от начала страницы. Отсюда классическая ошибка: забыли relative у карточки, и бейдж прилип к углу страницы.

Соседи абсолютного элемента ведут себя так, будто его нет: они займут его место. Ширина абсолютного элемента по умолчанию — по содержимому, а left: 0; right: 0 растягивают его на всю ширину контейнера.

/* затемнение поверх картинки на всю карточку */
.card { position: relative; }
.card::after {
  content: "";
  position: absolute;
  inset: 0;            /* top, right, bottom, left = 0 */
  background: linear-gradient(transparent, rgb(0 0 0 / .6));
}

inset — короткая запись всех четырёх координат. Подробнее о ::after — на странице псевдоэлементы ::before и ::after.

Как отцентровать абсолютный элемент

.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

top: 50% ставит в центр верхний край, а translate(-50%, -50%) сдвигает элемент назад на половину его собственной ширины и высоты. Если размеры элемента заданы, работает и другой способ: inset: 0; margin: auto;.

fixed: привязка к окну

position: fixed держит элемент на одном месте экрана при прокрутке: кнопка чата, шапка, cookie-плашка. Фиксированный элемент вынут из потока, поэтому контенту под фиксированной шапкой нужен отступ сверху, иначе первый заголовок спрячется.

Ловушка: если у любого предка есть transform, filter или perspective, fixed начинает отсчитываться от этого предка, а не от окна. Модальное окно внутри анимированного блока внезапно уезжает вместе с ним. Выноси такие окна ближе к body или используй тег dialog.

sticky: прилипание при прокрутке

.toc {
  position: sticky;
  top: 24px;
  align-self: start; /* если родитель — flex или grid */
}

Sticky-элемент ведёт себя как обычный, пока край области прокрутки не дойдёт до top: 24px, а затем прилипает. Прилипание длится, пока виден его родитель: родитель уехал — элемент уезжает вместе с ним.

Почему sticky «не работает»: не задано top; у предка стоит overflow: hidden или auto и прокрутка идёт не там; родитель не выше самого элемента, и прилипать некуда; во flex- или grid-контейнере элемент растянут на всю высоту — помогает align-self: start.

z-index и контекст наложения

z-index задаёт, кто окажется сверху. Он работает у позиционированных элементов (кроме static) и у детей flex- и grid-контейнеров. Сравниваются значения только внутри одного контекста наложения.

Новый контекст наложения создают, например: позиционированный элемент с z-index не auto, opacity меньше 1, transform, filter. Если карточка создала свой контекст, её всплывашка с z-index: 9999 всё равно окажется под соседней карточкой с z-index: 2: сравниваются карточки, а не их дети.

:root {
  --z-dropdown: 10;
  --z-header: 20;
  --z-modal: 30;
}
.header { position: sticky; top: 0; z-index: var(--z-header); }

Короткая шкала в переменных понятнее, чем гонка чисел 999 и 99999.

relative или absolute

relative

Остаётся в потоке, место сохраняется. Нужен как точка отсчёта для детей и для z-index.

absolute

Вынут из потока, соседи его не видят. Для бейджей, иконок, крестиков и наложений внутри контейнера.

Как найти контейнер в DevTools

Если абсолютный элемент встал не туда, выдели его в DevTools и поднимайся по дереву вверх, проверяя у предков вкладку Computed → position. Первый предок не со static — это и есть контейнер. Для sticky проверь у предков overflow.

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

  • Забывают position: relative у карточки, и бейдж улетает в угол страницы.
  • Строят всю страницу на absolute: при увеличении шрифта блоки наезжают друг на друга.
  • Ставят z-index: 99999, не зная, что элементы в разных контекстах наложения.
  • Пишут sticky без top или внутри предка с overflow: hidden.
  • Не оставляют отступ под фиксированной шапкой, и она закрывает первый заголовок.

Доступность

Абсолютно и фиксированно позиционированные элементы не должны перекрывать текст и поля при увеличении шрифта до 200%. Фиксированные панели на телефоне съедают и без того маленький экран — делай их невысокими и закрываемыми. Визуальное положение не меняет порядок фокуса: кнопка закрытия, нарисованная в углу, в HTML должна стоять там, где её логично встретить клавиатурой.

Поддержка браузерами

static, relative, absolute и fixed работают везде. sticky поддерживается всеми актуальными браузерами. Свойство inset — современное и тоже доступно в свежих версиях; для очень старых браузеров пиши четыре координаты по отдельности.

Практика

Сделай карточку урока с бейджем «Новое» в правом верхнем углу (отступ 12px) и затемнением снизу картинки. Рядом — оглавление, которое прилипает на 24px от верха при прокрутке. Шапку сайта закрепи сверху так, чтобы она не закрывала заголовок страницы.

Показать решение
.card { position: relative; }
.card .badge { position: absolute; top: 12px; right: 12px; }
.card::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 40%;
  background: linear-gradient(transparent, rgb(0 0 0 / .5));
}
.toc { position: sticky; top: 24px; align-self: start; }
.header { position: sticky; top: 0; z-index: 20; background: #fff; }

Открыть песочницу

Частые вопросы

Почему absolute-элемент прилип к углу страницы?

У его предков нет position, отличного от static, поэтому координаты считаются от начала страницы. Добавь position: relative контейнеру, внутри которого должен стоять элемент.

Чем fixed отличается от sticky?

fixed всегда держится за окно и вынут из потока. sticky остаётся в потоке и прилипает, только пока виден его родитель.

Почему не работает position: sticky?

Чаще всего не задано top, у предка стоит overflow: hidden, или родитель не выше самого элемента. Во flex-контейнере добавь align-self: start.

Почему z-index не поднимает элемент наверх?

Элемент находится в другом контексте наложения: его родитель с transform, opacity или собственным z-index сравнивается с соседями целиком. Поднимай родителя, а не ребёнка.

Можно ли сверстать сетку страницы через absolute?

Технически да, но это хрупко: блоки не знают друг о друге и наезжают при другом шрифте или экране. Сетку строят Grid и Flexbox.

Источники

Практикум по теме