Урок 5.1: Позиционирование
Модуль 5 — Продвинутый CSS
position: relative — сдвиг относительно своего места
Ты уже умеешь располагать элементы с помощью flexbox и margin'ов. Но что, если нужно сдвинуть элемент чуть-чуть в сторону, не влияя на соседей? Для этого существует position: relative.
Когда ты задаёшь элементу position: relative, он остаётся в потоке документа (то есть занимает своё обычное место), но ты можешь сдвинуть его относительно этого места с помощью свойств top, bottom, left, right.
.box {
position: relative;
top: 20px; /* сдвиг вниз на 20px */
left: 30px; /* сдвиг вправо на 30px */
/* или */
bottom: 10px; /* сдвиг вверх (от низа) */
right: 15px; /* сдвиг влево (от правого края) */
}
Важно: original место элемента остаётся занятым. Соседние элементы не «замечают» сдвига — они стоят так, будто элемент на своём месте. Он просто рисуется со смещением.
Видишь, средний блок съехал вниз и вправо, а остальные стоят как ни в чём не бывало. Они даже не знают, что средний блок сдвинулся — он по-прежнему занимает своё исходное место в потоке.
Но главная суперсила position: relative не в этом. Она в том, что он становится точкой отсчёта для абсолютно позиционированных детей. Об этом — в следующем разделе.
position: relative без сдвигов (просто position: relative) на родителе, если хочешь, чтобы дочерний position: absolute считал координаты от этого родителя. Это самый частый паттерн.
position: absolute — привязать к родителю
Абсолютное позиционирование — это когда элемент вырывается из потока документа и «приклеивается» к ближайшему position: relative (или к окну браузера, если такого родителя нет).
.parent {
position: relative; /* точка отсчёта */
}
.child {
position: absolute;
top: 20px; /* 20px от верха родителя */
right: 10px; /* 10px от правого края родителя */
}
Когда элемент получает position: absolute, он:
- Исчезает из потока — соседние элементы его не видят и занимают его место
- Привязывается к ближайшему родителю с
position: relative(илиabsolute, илиfixed) - Если такого родителя нет — привязывается к окну браузера
- Его ширина по умолчанию сжимается под содержимое
- Ты можешь указывать
top,bottom,left,right
top 20px, right 20px
Обрати внимание: абсолютный блок находится в правом верхнем углу контейнера. Второй обычный блок встал прямо под первый, будто абсолютного и не было — потому что его нет в потоке.
Классический пример использования absolute — это бейдж «скидка» на карточке товара:
<div class="product-card">
<div class="badge">-20%</div>
<img src="product.jpg" alt="Товар">
<h3>Название</h3>
<p>Цена: 1000 ₽</p>
</div>
<style>
.product-card {
position: relative;
/* ... стили карточки ... */
}
.badge {
position: absolute;
top: 10px;
left: 10px;
background: #e94560;
color: #fff;
padding: 4px 12px;
border-radius: 6px;
font-weight: bold;
}
</style>
Бейдж приклеивается к левому верхнему углу карточки независимо от содержимого. Хоть картинка, хоть текст — бейдж всегда будет на своём месте.
Ещё один частый паттерн — центрирование абсолютного элемента. Если задать top: 50%; left: 50% и сдвинуть обратно на половину своей ширины/высоты через transform:
.centered-absolute {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
Это старый способ центрирования, который работал задолго до flexbox. Сейчас его используют реже, но иногда без него не обойтись (например, когда элемент должен быть поверх всего с position: absolute).
🎉 Привет!
Это абсолютно отцентрированный блок внутри родителя. top: 50%, left: 50%, transform: translate(-50%, -50%).
ЗакрытьБлок выше отцентрирован внутри серого полупрозрачного overlay. Родитель имеет position: relative, а блок — position: absolute с top: 50%; left: 50%; transform: translate(-50%, -50%).
position: fixed — привязать к окну браузера
position: fixed похож на absolute, но с одним важным отличием: элемент привязывается к окну браузера, а не к родителю. И он не двигается при прокрутке страницы.
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background: #333;
color: #fff;
z-index: 100;
}
Этот хедер будет всегда сверху, даже если прокрутить страницу вниз на 10000 пикселей.
Fixed-элементы используются для:
- Шапка сайта (header) — всегда видна при прокрутке
- Кнопка «Наверх» — плавает в углу экрана
- Cookie-уведомления — приклеиваются к низу экрана
- Боковые панели — всегда на месте
body {
padding-top: 60px; /* чтобы контент не прятался под fixed-хедером */
}
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background: #1a1a2e;
color: #fff;
z-index: 1000;
display: flex;
align-items: center;
padding: 0 24px;
}
Fixed-элемент не занимает места в потоке, поэтому контент «залезает» под него. Чтобы это исправить, добавляют padding-top или margin-top на следующий элемент.
z-index для fixed-элементов. Хедер должен быть выше всего остального, иначе какой-нибудь другой элемент может перекрыть его. z-index: 1000 — стандартное значение для хедера.
z-index — кто выше
Когда элементы начинают накладываться друг на друга (absolute, fixed, relative со сдвигом), возникает вопрос: кто из них сверху? За это отвечает z-index.
.element {
position: relative;
z-index: 10; /* чем больше, тем выше */
}
z-index работает только на элементах с position: relative, absolute, fixed или sticky. На статичных элементах он игнорируется.
Представь, что элементы лежат стопкой. Чем выше z-index, тем выше элемент в стопке. По умолчанию z-index равен auto (или 0). Элементы с одинаковым z-index накладываются в порядке появления в HTML (тот, что позже — выше).
Красный блок (z-index: 1) — самый нижний. Зелёный (z-index: 2) — поверх него. Фиолетовый (z-index: 3) — самый верхний. Если поменять им z-index местами, изменится и порядок наложения.
Важный нюанс: контекст наложения (stacking context). Если у родителя есть z-index, его дети не могут «перепрыгнуть» через другой родительский элемент с более высоким z-index. Иерархия контекстов:
<!-- Пример контекста наложения -->
<div style="position:relative; z-index:10;">
<div style="position:absolute; z-index:9999;">
Этот элемент НЕ может быть выше родителя другого контекста
</div>
</div>
<div style="position:relative; z-index:5;">
<div style="position:absolute; z-index:1;">
Этот элемент ниже, хотя у его ребёнка z-index больше
</div>
</div>
На практике это означает: если ты задал z-index: 9999 на элементе, а он всё равно под чем-то, — проверь, не находится ли он внутри контейнера с меньшим z-index, чем у того, под чем он оказался.
z-index: 999999 в надежде, что это перебьёт всё. Проблема обычно не в числе, а в контексте наложения. Организуй z-index по смыслу: хедер — 100, модалка — 200, тултип — 300.
Правильная организация z-index может выглядеть так:
/* Уровни z-index */
--z-dropdown: 100;
--z-sticky: 200;
--z-fixed: 300;
--z-modal-overlay: 400;
--z-modal: 500;
--z-tooltip: 600;
--z-toast: 700;
Это CSS-переменные (кастомные свойства), которые задают системные уровни. Так ты всегда знаешь, какие значения используются, и не гадаешь, почему z-index: 9999 не работает.
Практика: модальное окно по центру, фиксированный хедер
Давай соберём всё вместе и сделаем страницу с фиксированным хедером и модальным окном по центру. Это два самых частых паттерна позиционирования в вебе.
Вот полный код. Скопируй, сохрани как HTML и открой в браузере:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Модальное окно + хедер</title>
<style>
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
margin: 0;
padding-top: 64px;
background: #f5f5f5;
color: #333;
}
/* Фиксированный хедер */
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 64px;
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: #fff;
display: flex;
align-items: center;
padding: 0 24px;
z-index: 1000;
box-shadow: 0 2px 12px rgba(0,0,0,0.2);
}
.header .logo {
font-size: 1.3em;
font-weight: bold;
margin-right: 32px;
}
.header nav a {
color: #ccc;
text-decoration: none;
margin-right: 20px;
font-size: 0.95em;
}
.header nav a:hover {
color: #fff;
}
/* Контент */
.content {
max-width: 700px;
margin: 0 auto;
padding: 40px 20px;
}
.content h1 {
font-size: 2em;
margin-bottom: 20px;
}
.content p {
line-height: 1.8;
margin-bottom: 16px;
color: #555;
}
.open-modal-btn {
display: inline-block;
padding: 14px 32px;
background: linear-gradient(135deg, #e94560, #c23152);
color: #fff;
border: none;
border-radius: 10px;
font-size: 1em;
cursor: pointer;
transition: transform 0.2s;
}
.open-modal-btn:hover {
transform: scale(1.03);
}
/* Оверлей модалки */
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 2000;
justify-content: center;
align-items: center;
}
.modal-overlay.active {
display: flex;
}
/* Модальное окно */
.modal {
background: #fff;
border-radius: 16px;
padding: 36px 32px;
max-width: 420px;
width: 90%;
position: relative;
box-shadow: 0 12px 40px rgba(0,0,0,0.2);
animation: modal-in 0.25s ease-out;
}
@keyframes modal-in {
from {
opacity: 0;
transform: scale(0.9) translateY(10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.modal h2 {
margin: 0 0 12px;
font-size: 1.5em;
color: #333;
}
.modal p {
color: #666;
line-height: 1.6;
margin: 0 0 24px;
}
.modal-close {
position: absolute;
top: 14px;
right: 18px;
background: none;
border: none;
font-size: 1.4em;
color: #999;
cursor: pointer;
transition: color 0.2s;
}
.modal-close:hover {
color: #e94560;
}
.modal-actions {
display: flex;
gap: 12px;
}
.modal-actions button {
flex: 1;
padding: 12px;
border-radius: 8px;
border: none;
font-size: 0.95em;
cursor: pointer;
}
.modal-actions .btn-primary {
background: linear-gradient(135deg, #e94560, #c23152);
color: #fff;
}
.modal-actions .btn-secondary {
background: #f0f0f0;
color: #555;
}
</style>
</head>
<body>
<!-- Fixed Header -->
<header class="header">
<div class="logo">⭐ MySite</div>
<nav>
<a href="#">Главная</a>
<a href="#">О нас</a>
<a href="#">Услуги</a>
<a href="#">Контакты</a>
</nav>
</header>
<!-- Content -->
<main class="content">
<h1>Добро пожаловать!</h1>
<p>
Этот демо-проект показывает, как работает фиксированный хедер и модальное окно. Хедер приклеен к верху страницы с помощью position: fixed. Он не двигается при прокрутке.
</p>
<p>
Модальное окно открывается по клику на кнопку. Оно использует position: fixed для оверлея (чтобы он был на весь экран) и центрирование через flexbox.
</p>
<p>
Обрати внимание: body имеет padding-top: 64px, чтобы контент не прятался под хедером. Если убрать этот padding, первый абзац окажется под хедером.
</p>
<button class="open-modal-btn" onclick="document.querySelector('.modal-overlay').classList.add('active')">
🖱️ Открыть модалку
</button>
<p style="margin-top:24px;">
Попробуй проскроллить страницу вниз. Хедер остаётся на месте. Это и есть магия position: fixed.
</p>
<p style="height:800px; color:#ccc; text-align:center; display:flex; align-items:center; justify-content:center;">
↓ Скролль вниз — хедер всё ещё на месте ↓
</p>
</main>
<!-- Modal Overlay -->
<div class="modal-overlay" onclick="if(event.target===this)this.classList.remove('active')">
<div class="modal">
<button class="modal-close" onclick="this.closest('.modal-overlay').classList.remove('active')">✕</button>
<h2>💬 Привет!</h2>
<p>
Это модальное окно. Оно отцентрировано по центру экрана с помощью flexbox на оверлее (display: flex; align-items: center; justify-content: center). Модалка имеет position: relative (по умолчанию для flex-детей).
</p>
<div class="modal-actions">
<button class="btn-primary" onclick="alert('Действие выполнено!')">Подтвердить</button>
<button class="btn-secondary" onclick="this.closest('.modal-overlay').classList.remove('active')">Отмена</button>
</div>
</div>
</div>
</body>
</html>
Давай разберём, что мы используем из позиционирования:
- Хедер:
position: fixed; top: 0; left: 0; width: 100%; z-index: 1000— всегда сверху, не прокручивается - Body:
padding-top: 64px— чтобы контент был виден под хедером - Оверлей:
position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 2000— перекрывает всю страницу, включая хедер - Модалка: не имеет position, но центрируется через
display: flexна оверлее сalign-items: center; justify-content: center - Кнопка закрытия:
position: absolute; top: 14px; right: 18px— в правом верхнем углу модалки
Обрати внимание на z-index: хедер 1000, оверлей 2000. Если бы оверлей был меньше (например, 500), хедер был бы поверх оверлея. Всегда проверяй z-index, когда что-то перекрывает то, что не должно.
А вот ещё один пример — плавающая кнопка «Наверх» (back to top). Она очень удобна на длинных страницах:
<button class="back-to-top" onclick="window.scrollTo({top:0,behavior:'smooth'})">
↑ Наверх
</button>
<style>
.back-to-top {
position: fixed;
bottom: 30px;
right: 30px;
background: #e94560;
color: #fff;
border: none;
padding: 14px 20px;
border-radius: 50%;
width: 56px;
height: 56px;
font-size: 1.2em;
cursor: pointer;
box-shadow: 0 4px 12px rgba(233,69,96,0.4);
z-index: 999;
transition: transform 0.2s, opacity 0.2s;
}
.back-to-top:hover {
transform: scale(1.1);
}
</style>
Эта кнопка всегда в правом нижнем углу экрана. position: fixed удерживает её на месте при прокрутке. z-index: 999 гарантирует, что она поверх контента, но под модалкой (у которой z-index 2000). Иерархия соблюдена.
Давай подведём итог. Вот шпаргалка по позиционированию:
/* ПОЗИЦИОНИРОВАНИЕ — ШПАРГАЛКА */
/* Относительное — сдвиг относительно своего места */
.relative {
position: relative;
top: 10px;
left: 20px;
}
/* Абсолютное — привязка к родителю с position */
.absolute {
position: absolute;
top: 0;
right: 0;
}
/* Фиксированное — привязка к окну */
.fixed {
position: fixed;
top: 0;
left: 0;
width: 100%;
}
/* Центрирование absolute */
.center-absolute {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* Кто выше */
.z-index {
z-index: 100;
}
Главное, что нужно запомнить:
position: relative— сдвигает элемент, не вынимая из потока, и служит точкой отсчёта для absoluteposition: absolute— вынимает из потока, привязывается к ближайшему relative-родителюposition: fixed— привязывается к окну, не двигается при прокруткеz-index— кто выше (работает только с position)- Не забывай padding-top для body при фиксированном хедере
- Организуй z-index системно: хедер 100, оверлей 200, модалка 300
Позиционирование — мощный инструмент. С ним ты можешь создавать сложные интерфейсы: выпадающие меню, тултипы, модалки, фиксированные шапки. В следующем уроке мы разберём анимации — сделаем эти интерфейсы живыми и плавными.
Урок 5.1: Позиционирование
5 вопросов