position в CSS определяет, как элемент располагается на странице — в обычном потоке документа или поверх него. Пять значений: static, relative, absolute, fixed, sticky — каждое для своей задачи.

- position: static — нормальный поток (по умолчанию)
- position: relative — сдвиг с сохранением места
- position: absolute — точное позиционирование
- position: fixed — фиксирован к экрану
- position: sticky — прилипающий элемент
- z-index — порядок наслоения
- Сравнение всех типов позиционирования
- Практические паттерны
- Часто задаваемые вопросы о CSS position
- position: absolute не работает — почему?
- position: sticky не прилипает — как исправить?
- z-index не работает — частые причины
position: static — нормальный поток (по умолчанию)
Все элементы по умолчанию имеют position: static. Элемент находится в обычном потоке документа. Свойства top, left, right, bottom и z-index не работают.
div { position: static; } /* значение по умолчанию, можно не писать */
/* top/left/right/bottom НЕ работают при static */
/* z-index НЕ работает при static */

position: relative — сдвиг с сохранением места
Элемент сдвигается относительно своего нормального положения. Важно: место в потоке документа сохраняется — соседние элементы не двигаются. Чаще используется как контейнер для absolute-детей.
.box {
position: relative;
top: 10px; /* сдвинуть вниз на 10px от обычного места */
left: 20px; /* сдвинуть вправо на 20px */
}
/* Место в потоке СОХРАНЯЕТСЯ — «дыра» остаётся */
/* Главное применение: контейнер для absolute детей */
.card {
position: relative; /* ← теперь это точка отсчёта для absolute внутри */
}
.card .badge {
position: absolute; /* позиционируется относительно .card */
top: 10px;
right: 10px;
}

position: absolute — точное позиционирование
Элемент убирается из потока — не занимает места. Позиционируется относительно ближайшего предка с position ≠ static. Если такого нет — относительно <html>.
/* Правило: нужен родитель с position: relative */
.container {
position: relative; /* ← точка отсчёта */
}
.tooltip {
position: absolute;
top: -40px; /* 40px выше верха родителя */
left: 50%;
transform: translateX(-50%); /* центрирование */
}
/* Overlay на всю карточку */
.card {
position: relative;
overflow: hidden;
}
.card-overlay {
position: absolute;
inset: 0; /* = top:0; right:0; bottom:0; left:0 */
background: rgba(0, 0, 0, 0.5);
opacity: 0;
transition: opacity 0.3s;
}
.card:hover .card-overlay {
opacity: 1;
}
/* Центрировать absolute элемент в родителе */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* сдвиг на половину своего размера */
}
/* Прижать к краям */
.bottom-right {
position: absolute;
bottom: 16px;
right: 16px;
}

position: fixed — фиксирован к экрану
Элемент позиционируется относительно viewport (экрана браузера) и не прокручивается вместе со страницей. Используется для навбаров, кнопок «вверх», чатов, cookie-баннеров.
/* Фиксированный навбар */
.header {
position: fixed;
top: 0;
left: 0;
right: 0; /* растянуть на всю ширину */
height: 64px;
background: white;
border-bottom: 1px solid #e5e7eb;
z-index: 100;
}
/* Важно: контент прячется под fixed navbar */
/* Добавь отступ к body: */
body { padding-top: 64px; }
/* Кнопка "вернуться наверх" */
.scroll-top {
position: fixed;
bottom: 32px;
right: 32px;
width: 48px;
height: 48px;
background: #2563eb;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 50;
}
/* Cookie-баннер снизу */
.cookie-banner {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #1e293b;
color: white;
padding: 16px 24px;
z-index: 200;
}

position: sticky — прилипающий элемент
Сначала ведёт себя как relative, но когда при прокрутке достигает заданного порога — «прилипает» и ведёт себя как fixed. Идеален для сайдбаров, заголовков таблиц, навигации по странице.
/* Прилипающий сайдбар */
.sidebar {
position: sticky;
top: 80px; /* прилипает когда 80px от верха viewport */
/* Работает пока родитель .sidebar виден */
align-self: start; /* важно в flex/grid контейнере */
}
/* Прилипающий заголовок таблицы */
table thead th {
position: sticky;
top: 0;
background: white; /* важно! иначе контент просвечивает сквозь */
z-index: 1;
}
/* Прилипающие буквы в алфавитном списке (как в контактах) */
.letter-header {
position: sticky;
top: 0;
background: #f3f4f6;
padding: 8px 16px;
font-weight: 700;
}
/* Прилипающий CTA в боковой колонке */
.cta-block {
position: sticky;
top: 100px;
}

Sticky не работает, если:
- У родителя задано
overflow: hiddenилиoverflow: auto - Не задано хотя бы одно из:
top,bottom,left,right - Родитель занимает ровно столько же места, что и сам элемент
z-index — порядок наслоения
z-index управляет порядком наслоения позиционированных элементов. Работает только с position ≠ static. Большее значение — ближе к зрителю.
/* Стандартная схема z-index */
:root {
--z-base: 1;
--z-dropdown: 10;
--z-sticky: 20;
--z-overlay: 100;
--z-modal: 101;
--z-toast: 200;
}
.header { z-index: var(--z-sticky); }
.dropdown { z-index: var(--z-dropdown); }
.overlay { z-index: var(--z-overlay); }
.modal { z-index: var(--z-modal); }
.toast { z-index: var(--z-toast); }
/* z-index НЕ работает для position: static */
div { position: static; z-index: 999; } /* не сработает! */
/* Нужно добавить position */
div { position: relative; z-index: 999; } /* ✅ */

Сравнение всех типов позиционирования
| position | В потоке? | top/left/right/bottom | Прокрутка | Относительно |
|---|---|---|---|---|
static | Да | Нет | — | — |
relative | Да | Да | Да | Своего нормального места |
absolute | Нет | Да | Да | Ближайшего не-static предка |
fixed | Нет | Да | Нет | Viewport (экран) |
sticky | Да* | Да (порог) | До порога | Viewport (после порога) |

Практические паттерны
/* 1. Badge (уведомление) на иконке */
.icon-wrapper {
position: relative;
display: inline-flex;
}
.notification-badge {
position: absolute;
top: -4px;
right: -4px;
width: 18px;
height: 18px;
background: #dc2626;
color: white;
font-size: 11px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid white; /* белая обводка для разделения с иконкой */
}
/* 2. Hover overlay на картинке */
.image-card {
position: relative;
overflow: hidden;
border-radius: 12px;
}
.image-card img {
width: 100%;
display: block;
transition: transform 0.3s;
}
.image-card:hover img {
transform: scale(1.05);
}
.image-card-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%);
display: flex;
align-items: flex-end;
padding: 20px;
opacity: 0;
transition: opacity 0.3s;
}
.image-card:hover .image-card-overlay {
opacity: 1;
}
/* 3. Dropdown меню */
.nav-item {
position: relative;
}
.dropdown-menu {
position: absolute;
top: 100%; /* сразу под родителем */
left: 0;
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
min-width: 200px;
display: none;
}
.nav-item:hover .dropdown-menu {
display: block;
}

Часто задаваемые вопросы о CSS position
position: absolute не работает — почему?
Почти всегда причина — нет родителя с position: relative (или другим не-static значением). Без такого родителя absolute элемент позиционируется относительно <html> — всей страницы, а не вашего контейнера. Решение: добавь position: relative к нужному родительскому элементу. Проверь в DevTools — в панели Computed видно относительно какого предка позиционируется элемент.

position: sticky не прилипает — как исправить?
Три самые частые причины: 1) Не задан top (или другое направление) — он обязателен, без него sticky не знает когда прилипать. 2) У родителя стоит overflow: hidden или overflow: auto — это ломает sticky. Убери overflow или замени на overflow: clip. 3) Родитель слишком маленький — sticky работает пока родитель виден на экране, если родитель сам по себе занимает ровно одну viewport — прилипать некуда.

z-index не работает — частые причины
z-index работает только для позиционированных элементов (position ≠ static). Если элемент static — z-index игнорируется. Вторая причина: stacking context (контекст наслоения). Когда элемент имеет opacity < 1, transform, filter или isolation: isolate — создаётся новый stacking context, и z-index работает только внутри него. Решение: либо убери эти свойства с родителя, либо задай нужный z-index на самом родителе.



