Урок · CSS
position: точное расположение элемента
Свойство 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
Остаётся в потоке, место сохраняется. Нужен как точка отсчёта для детей и для z-index.
Вынут из потока, соседи его не видят. Для бейджей, иконок, крестиков и наложений внутри контейнера.
Как найти контейнер в 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.
Источники
Практикум по теме
- Шапка, которая остаётся при прокрутке — Длинный урок увозит меню вверх. Липкая шапка оставляет ссылки под рукой.