CSS position: что нужно знать до первого залипшего блока
Пять значений свойства position решают, где окажется блок и относительно чего он смещается. Разбираем, чем они отличаются на практике, и почему top: 20px иногда не двигает элемент.

К концу этой статьи вы поймёте, чем absolute отличается от fixed, почему top и left иногда вообще ничего не делают, и как заставить блок прилипнуть к верху экрана при прокрутке. На разбор уйдёт минут пятнадцать, все примеры можно вставить в любой HTML-файл и открыть в браузере. Актуально для всех современных браузеров — Chrome, Firefox, Safari; position: sticky работает везде начиная примерно с 2019 года.
Свойство position управляет тем, как элемент располагается в потоке документа и относительно чего считаются смещения top, right, bottom, left. У него пять значений: static, relative, absolute, fixed, sticky. Путаница между ними — причина большинства ситуаций «я написал top, а блок стоит на месте».
Что нужно понять до начала
Три вещи, без которых свойства смещения ведут себя необъяснимо:
- Смещения работают не всегда.
top,leftи остальные влияют на элемент только если у негоpositionотличается отstatic. Уstaticони игнорируются молча — ошибки в консоли не будет. - Есть «содержащий блок» (containing block). Именно относительно его границ отсчитываются смещения. У
absoluteэто ближайший предок сpositionне равнымstatic; если такого нет — окно браузера. - Поток документа.
static,relativeиstickyзанимают место в потоке — соседние элементы их «видят».absoluteиfixedиз потока выпадают, будто их нет, и другие блоки могут наехать на их место.
Пять значений по порядку
static — значение по умолчанию
Так расположены все элементы, пока вы не написали иное. Блок стоит там, где ему положено по потоку. Смещения не действуют. Отдельно position: static пишут редко — разве что чтобы отменить заданное ранее значение.
relative — сдвиг от собственного места
Элемент остаётся в потоке и занимает своё место, но визуально смещается относительно исходной позиции. Важный нюанс: место в потоке за ним сохраняется, соседи ведут себя так, будто он не двигался.
<div class="box">Первый</div>
<div class="box shifted">Второй</div>
<div class="box">Третий</div>
<style>
.box { width: 120px; height: 60px; background: #dde; margin: 8px; }
.shifted {
position: relative;
top: 20px; /* сдвиг вниз на 20px от исходной позиции */
left: 30px; /* сдвиг вправо на 30px */
}
</style>
Проверка: второй блок съедет вниз-вправо, но между первым и третьим останется пустое место — там, где второй «был бы». Чаще всего relative используют не ради смещения, а чтобы сделать элемент содержащим блоком для вложенного absolute.
absolute — привязка к предку
Элемент выпадает из потока и позиционируется относительно ближайшего предка, у которого position не static. Если такого предка нет — относительно корня страницы. Это самая частая причина багов: вы ждёте, что блок ляжет внутри карточки, а он улетает в угол экрана, потому что у карточки не задано position: relative.
<div class="card">
<span class="badge">NEW</span>
Текст карточки
</div>
<style>
.card {
position: relative; /* без этой строки badge улетит в угол окна */
width: 200px;
padding: 16px;
background: #eee;
}
.badge {
position: absolute;
top: 8px;
right: 8px;
background: crimson;
color: #fff;
padding: 2px 6px;
}
</style>
Проверка: значок NEW прижмётся к правому верхнему углу серой карточки. Уберите position: relative у .card — значок прыгнет в угол всей страницы.
fixed — привязка к окну браузера
Похоже на absolute, но точка отсчёта — окно (viewport), а не предок. Блок остаётся на месте при прокрутке. Так делают «плавающие» кнопки, куки-баннеры, шапки, которые всегда видны.
.cookie-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0; /* растянуть по всей ширине окна */
padding: 12px;
background: #222;
color: #fff;
}
Подводный камень: если у любого предка задано свойство transform, filter или perspective с ненулевым значением, точкой отсчёта для fixed становится этот предок, а не окно. Блок перестаёт «прилипать» к экрану, и это выглядит как поломка на пустом месте.
sticky — гибрид relative и fixed
Пока элемент в зоне видимости — ведёт себя как relative, стоит в потоке. Как только при прокрутке он достигает заданного порога (например, top: 0) — прилипает и ведёт себя как fixed, пока родитель не уедет за пределы экрана.
.section-title {
position: sticky;
top: 0; /* обязателен хотя бы один порог, иначе не залипнет */
background: #fff;
padding: 8px;
}
Проверка: заголовок раздела прокручивается вместе со страницей, а дойдя до верха окна — замирает там, пока виден его раздел. Без указанного top (или другого порога) sticky не сработает вообще — это самая частая ошибка новичков.
Правило, которое экономит часы отладки: если смещениеtop/leftне действует — сначала проверьте, задан ли элементуposition, отличный отstatic. В девяти случаях из десяти проблема здесь.
Сравнение значений
| Значение | В потоке? | Точка отсчёта смещений | Двигается при прокрутке? |
|---|---|---|---|
| static | да | смещения не работают | да |
| relative | да (место сохраняется) | собственная исходная позиция | да |
| absolute | нет | ближайший предок не-static | да, вместе со страницей |
| fixed | нет | окно браузера | нет, стоит на месте |
| sticky | да, до порога | ближайший прокручиваемый предок | до порога — да, потом залипает |
z-index — кто окажется сверху
Когда позиционированные блоки накладываются, порядок наложения задаёт z-index. Важное ограничение: z-index действует только на элементы с position не равным static. Если написать z-index: 999 статичному блоку — ничего не изменится. Большее число — ближе к зрителю.
Отдельная тема — контексты наложения (stacking contexts): z-index сравнивается только внутри одного контекста, и transform или opacity у предка создают новый. Здесь мы её только обозначаем, разбор оставим отдельно.
Если не получилось
- Написал
top: 20px, блок не двигается. У элементаposition: static(по умолчанию). Задайтеrelative,absoluteилиfixed. - Absolute-блок улетел в угол страницы. У ближайшего предка нет
position: relative. Добавьте его тому контейнеру, внутри которого хотите позиционировать. - Sticky не залипает. Не задан порог (
top,bottomи т.п.), либо у родителя стоитoverflow: hidden, либо высота родителя равна высоте самого элемента — прилипать некуда. - Fixed прокручивается вместе со страницей. У одного из предков есть
transform,filterилиperspective— он перехватил роль точки отсчёта. - z-index не помогает поднять блок наверх. Либо у элемента
position: static, либо элементы в разных контекстах наложения — сравнивать ихz-indexнапрямую нельзя.
Что делать дальше
Соберите одну страницу, где встречаются все пять значений: карточка с absolute-значком, залипающий sticky-заголовок, fixed-кнопка «наверх». На ней вы быстрее прочувствуете разницу, чем по любой таблице. Дальше стоит разобраться с контекстами наложения (stacking context) — без этого z-index в больших проектах остаётся непредсказуемым. И посмотрите на Flexbox и Grid: большую часть раскладок, ради которых раньше тянулись к position, сегодня удобнее делать именно ими, а position оставить точечным наложениям.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: MDN Web Docs — position, CSS Positioned Layout Module Level 3 (W3C)
Частые вопросы
Чем absolute отличается от fixed простыми словами?
Почему мой sticky-элемент не прилипает?
А если у меня старый браузер — position: sticky сработает?
Почему z-index не поднимает блок наверх, хотя число большое?
Мой fixed-блок вдруг перестал прилипать к экрану, что случилось?
Что использовать для раскладки страницы — position или Flexbox/Grid?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.