Skip to content

Latest commit

 

History

History
478 lines (319 loc) · 26.2 KB

File metadata and controls

478 lines (319 loc) · 26.2 KB

Урок 9. Свойство position: static, relative, absolute, fixed, sticky

Что делает position

Свойство position определяет, как элемент располагается на странице: остаётся ли он в обычном потоке документа или «вынимается» из него и позиционируется вручную через top/left/right/bottom. Понимание position — одна из базовых опор вёрстки: от него зависит поведение шапки сайта, всплывающих меню, рекламных блоков, модальных окон и многого другого.

Пять значений коротко:

  • static (по умолчанию) — элемент в обычном потоке, top/left/... не действуют.
  • relative — элемент остаётся в потоке (место зарезервировано), но его можно визуально сместить; также создаёт контекст позиционирования для дочерних absolute-элементов.
  • absolute — элемент полностью вынимается из потока, позиционируется относительно ближайшего «позиционированного» предка.
  • fixed — элемент вынимается из потока и закрепляется относительно окна просмотра (viewport), не двигается при прокрутке.
  • sticky — гибрид relative и fixed: ведёт себя как обычный элемент, пока не достигнет заданного порога прокрутки, а затем «прилипает» на этом месте.

Разберём каждое значение подробно.

html-разметка для урока:
<!DOCTYPE html>
<html lang="ru">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Практика Position</title>

    <link rel="stylesheet" href="style.css">
</head>

<body>

    <header>
        <nav>

            <ul>

                <li><a href="#">Главная</a></li>

                <li>

                    <a href="#">Курсы</a>

                    <ul class="dropdown">
                        <li><a href="#">HTML</a></li>
                        <li><a href="#">CSS</a></li>
                        <li><a href="#">JavaScript</a></li>
                    </ul>

                </li>

                <li><a href="#">Контакты</a></li>

            </ul>

        </nav>
    </header>

    <main>

        <h1>Изучаем position</h1>

        <section>

            <h2>Static / Relative</h2>

            <div class="box">
                Box
            </div>

            <p>
                Этот текст расположен после блока .box и позволит увидеть,
                как ведут себя элементы при использовании static и relative.
            </p>

        </section>


        <section>

            <h2>Absolute</h2>

            <article class="article">

                <div class="badge">
                    Badge
                </div>

                <div class="ad">
                    Реклама
                </div>

                <h3>Название статьи</h3>

                <p>
                    Здесь находится текст статьи. Именно относительно этого
                    контейнера будут позиционироваться абсолютные элементы.
                </p>

            </article>

        </section>


        <section>

            <h2>Абсолютное центрирование</h2>

            <div class="wrap">

                <div class="modal">
                    Modal window
                </div>

            </div>

        </section>


        <section>

            <h2 class="section-title">
                Первый раздел
            </h2>

            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>

        </section>


        <section>

            <h2 class="section-title">
                Второй раздел
            </h2>

            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>

        </section>


        <section>

            <h2 class="section-title">
                Третий раздел
            </h2>

            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>

        </section>

    </main>


    <button class="cta">
        Записаться
    </button>

</body>

</html>

position: static — поведение по умолчанию

Элемент остаётся в нормальном потоке документа, и свойства top/left/right/bottom на него не влияют вообще.

.box {
  position: static; /* значение по умолчанию — указывать явно не нужно */
  top: 20px; /* не сработает */
}

Большинство элементов страницы (параграфы, заголовки, обычные блоки) работают именно в этом режиме — static не назначают явно, к другим значениям переходят только тогда, когда нужно особое позиционирование. Частая ошибка новичков — ожидать, что top/left подвинут static-элемент; для этого сначала нужно сменить position на что-то ещё.


position: relative — смещение внутри потока и контекст для потомков

Элемент с position: relative не вынимается из потока — его место остаётся зарезервированным, соседние элементы ведут себя так, будто ничего не изменилось. При этом его можно визуально сдвинуть через top/left/right/bottom.

.box {
  position: relative;
  top: 20px; /* визуально сдвигается вниз, но исходное место остаётся пустым */
}

Вторая и более частая причина использовать relative — создание контекста позиционирования для дочерних элементов с position: absolute. Если внутри relative-родителя есть absolute-потомок, тот позиционируется относительно именно этого родителя (точнее, его padding box), а не относительно всей страницы.

.card {
  position: relative; /* контекст для .badge */
}

.badge {
  position: absolute;
  top: 8px;
  right: 8px;
}

Если убрать position: relative у .card, .badge привяжется к ближайшему предку, у которого position отличен от static — а если такого предка вообще нет, то к самой странице (начальному containing block), и «уедет» в угол экрана, а не карточки.

Ключевое правило, которое легко перепутать: relative не вынимает элемент из потока (в отличие от absolute) — если вы хотите, чтобы элемент не занимал место в документе, relative для этого не подходит.


position: absolute — вынимает из потока, позиционируется относительно предка

Элемент с position: absolute полностью удаляется из нормального потока — соседние элементы ведут себя так, будто его не существует. Его позиция вычисляется относительно ближайшего предка, у которого position отличен от static (этот предок называется containing block). Если такого предка нет — точкой отсчёта становится сама страница.

Практическое применение: баннер внутри карточки/статьи

<article class="article">
  <div class="ad">Реклама</div>
  <h1>Заголовок статьи</h1>
  <p>Текст статьи...</p>
</article>
.article {
  position: relative; /* контекст для .ad */
}

.ad {
  position: absolute;
  top: 12px;
  right: 12px;
}

Баннер .ad всегда остаётся привязанным именно к этой статье, где бы статья ни находилась на странице — потому что .article создаёт для него контекст позиционирования.

Практическое применение: выпадающее меню

nav li {
  position: relative;
}

.dropdown {
  position: absolute;
  top: 100%; /* сразу под пунктом меню */
  left: 0;
  display: none;
}

nav li:hover .dropdown {
  display: block;
}

top: 100% здесь означает «100% высоты родителя (li)» — то есть подменю выпадает ровно под пунктом навигации.

Центрирование абсолютного элемента

.wrap {
  position: relative;
}

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

left: 50%/top: 50% смещают верхний левый угол модального окна в центр родителя, а transform: translate(-50%, -50%) дополнительно сдвигает сам элемент на половину его собственной ширины и высоты назад — в результате центр самого модального окна оказывается точно в центре родителя. Это стандартный и самый предсказуемый приём центрирования абсолютно спозиционированных блоков.

Важные детали и подводные камни

Проценты в left/top у absolute-элемента вычисляются от размеров containing block, а не от размеров самого элемента — отсюда и нужен transform для точного центрирования, а не просто left: 50% само по себе.

Некоторые CSS-свойства у предков (transform, filter, will-change: transform) создают собственный контекст позиционирования — если absolute-элемент вдруг ведёт себя не так, как ожидалось (привязывается не к тому предку), в первую очередь проверьте, нет ли у промежуточных предков подобных свойств.

z-index работает в пределах конкретного контекста наложения (stacking context) — если кажется, что z-index «не действует», возможно, родитель уже создал отдельный контекст наложения, и сравнение z-index происходит не с теми элементами, с которыми ожидалось.


position: fixed — закреплён относительно окна просмотра

Элемент с position: fixed вынимается из потока и закрепляется относительно viewport — окна браузера. При прокрутке страницы он остаётся на том же самом месте экрана, независимо от того, что происходит с остальным содержимым.

Плавающая кнопка (CTA)

.cta {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 999;
}

Фиксированная шапка и компенсация перекрытия

Фиксированный header перекрывает верхнюю часть страницы, если явно не «отдать» ему место заранее:

header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 64px;
}

main {
  padding-top: 64px; /* компенсация — иначе контент окажется под шапкой */
}

Дополнительно полезно задать scroll-padding-top у html, чтобы переходы по внутренним якорным ссылкам (#section) тоже учитывали высоту фиксированной шапки и не «прятали» заголовок раздела под ней:

html {
  scroll-padding-top: 64px;
}

Важная ловушка: transform у предка меняет контекст для fixed

По умолчанию fixed всегда привязан к viewport, независимо от вложенности в DOM. Но если у какого-либо предка задано свойство, создающее новый контекст (transform, filter, perspective, will-change: transform), фиксированный элемент может неожиданно начать позиционироваться относительно этого предка, а не всего окна браузера. Если fixed-элемент ведёт себя не так, как ожидалось — в первую очередь проверьте стили промежуточных предков на предмет подобных свойств.

Производительность и доступность

Для анимации fixed-элементов лучше использовать transform/opacity, а не изменение top/left — это позволяет браузеру задействовать более быстрый путь рендеринга (композиция на GPU) вместо пересчёта раскладки страницы. Фиксированные элементы не должны перекрывать интерактивный контент (кнопки, поля форм) — особенно критично на мобильных экранах, где свободного места и так немного.


position: sticky — гибрид relative и fixed

position: sticky ведёт себя как обычный элемент в потоке документа (как relative) до тех пор, пока при прокрутке не достигнет заданного порога (обычно top: 0) — после этого он «прилипает» к этой позиции и остаётся видимым, пока пользователь не прокрутит мимо всего его ближайшего скроллящегося родителя.

Практический пример: заголовок раздела, прилипающий сверху при прокрутке

<section>
  <h2 class="section-title">Раздел А</h2>
  <p>Много текста...</p>
</section>

<section>
  <h2 class="section-title">Раздел Б</h2>
  <p>Ещё много текста...</p>
</section>
.section-title {
  position: sticky;
  top: 0;
  background: white;
  padding: 8px 0;
}

Пока страница прокручивается в пределах раздела, его заголовок остаётся строго вверху видимой области — а как только начинается следующий раздел, его заголовок «выталкивает» предыдущий и сам занимает прилипшую позицию.

Как работает порог прилипания

sticky-элемент требует хотя бы одного смещения (top, left, right или bottom) — именно оно задаёт порог, при достижении которого элемент «прилипает». Без указания хотя бы одного из этих свойств sticky фактически будет вести себя как обычный static.

Частые причины, по которым sticky «не работает»

У родителя задан overflow: hidden, overflow: auto или overflow: scroll. Прилипание работает относительно ближайшего скроллящегося предка — если у одного из предков задано подрезающее переполнение, оно может «сломать» прилипание, ограничив область, в которой элемент способен закрепиться, вплоть до полного отключения эффекта.

У родительского контейнера недостаточная высота. sticky-элемент прилипает и остаётся видимым только до тех пор, пока не «закончится» его непосредственный родительский блок — если родитель по высоте равен самому прилипающему элементу, то фактического «прилипания» просто не будет видно, потому что элементу некуда прилипать: он и так уже занимает всю высоту родителя.

Забыт explicit top (или другое смещение). Без указания хотя бы top: 0 браузер не поймёт, при каком именно пороге элемент должен начать прилипать.

Сравнение sticky и fixed

fixed закрепляется относительно всего окна браузера и остаётся видимым на протяжении всей страницы. sticky закрепляется только в пределах своего родительского блока — как только пользователь прокручивает мимо этого родителя целиком, прилипший элемент прокручивается вместе с ним дальше, а не остаётся навсегда видимым, как это было бы с fixed. sticky идеально подходит для заголовков разделов и элементов сайдбара, которые должны быть видны только пока пользователь находится в пределах конкретной секции контента.


Сравнительная таблица

Значение В потоке документа? Относительно чего позиционируется
static Да Не позиционируется, top/left не действуют
relative Да (место зарезервировано) Само себя (визуальное смещение от исходной позиции)
absolute Нет Ближайший предок с position ≠ static (или страница)
fixed Нет Окно просмотра (viewport), не меняется при прокрутке
sticky Да, пока не сработал порог Ближайший скроллящийся родитель, после порога — прилипает к viewport в его пределах

Вопросы для проверки

  1. Какое значение position используется по умолчанию у всех элементов, и что это значение означает практически?
  2. Что делает position: relative по отношению к обычному, статическому положению элемента?
  3. Может ли элемент с position: relative, смещённый через top, «вылезти» за пределы своего родителя и перекрыть соседние блоки?
  4. К чему привязывается элемент с position: absolute?
  5. Что произойдёт, если у элемента с position: absolute нет ни одного позиционированного предка?
  6. Чем position: fixed принципиально отличается от position: absolute?
  7. Что делает position: sticky, и чем оно отличается от fixed?
  8. Для чего в навигационном меню часто используют абсолютное позиционирование?
  9. Какое значение position лучше всего использовать, чтобы закрепить кнопку в правом нижнем углу экрана так, чтобы она оставалась видимой всегда, независимо от прокрутки страницы?
  10. Почему понимание разных режимов позиционирования особенно важно при вёрстке интерфейсов?

Практические задания

Задание 1. static vs relative — наглядная демонстрация

Создай два одинаковых блока div с одинаковым текстом. Первому не задавай position вообще (оставь static по умолчанию) и попробуй задать ему top: 30px. Второму явно задай position: relative; top: 30px;. Сравни результат и словами объясни в комментарии к CSS-файлу, почему первый блок не сдвинулся.


Задание 2. Бейдж на карточке (relative + absolute)

Создай карточку товара шириной 300px с заголовком и описанием. Добавь в правый верхний угол карточки бейдж «Новинка», используя position: relative у карточки и position: absolute у бейджа.


Задание 3. Выпадающее меню и центрированное модальное окно (absolute)

  1. Создай горизонтальную навигацию с тремя пунктами; у одного пункта добавь вложенный список-подменю. Подменю должно появляться при наведении и выпадать точно под пунктом.
  2. Отдельно создай блок-«окно» (контейнер с position: relative и фиксированной высотой) и центрируй внутри него модальное окно через absolute + transform: translate(-50%, -50%).

Задание 4. Плавающая кнопка и фиксированная шапка (fixed)

  1. Создай кнопку «Наверх», закреплённую в правом нижнем углу экрана через position: fixed, видимую при любой прокрутке страницы.
  2. Создай фиксированную шапку сайта высотой 64px и не забудь компенсировать перекрытие контента через padding-top у main.

Задание 5. Прилипающие заголовки разделов (sticky)

Создай страницу с тремя разделами (section), в каждом — заголовок и достаточно длинный текст для прокрутки. Сделай заголовки прилипающими сверху через position: sticky; top: 0; — так, чтобы при прокрутке заголовок текущего раздела оставался видимым, пока не начнётся следующий.


Задание 6. Итоговая практика — страница со всеми видами позиционирования

Собери законченную страницу:

  1. header с горизонтальной навигацией, у одного пункта — выпадающее подменю (absolute), сам header закреплён сверху через sticky.
  2. main с двумя статьями (static, обычное расположение) — каждая с заголовком, текстом и картинкой.
  3. Кнопка в правом нижнем углу страницы, закреплённая через fixed, всегда видимая при прокрутке.

Предыдущий урок | Следующий урок