7 июня 2022 г.

Свойство position

Свойство position позволяет сдвигать элемент со своего обычного места. Цель этой главы – не только напомнить, как оно работает, но и разобрать ряд частых заблуждений и граблей.

position: static

Статическое позиционирование производится по умолчанию, в том случае, если свойство position не указано.

Его можно также явно указать через CSS-свойство:

position: static;

Такая запись встречается редко и используется для переопределения других значений position.

Здесь и далее, для примеров мы будем использовать следующий документ:

<div style="background: #fee; width: 500px">
    Без позиционирования ("position: static").

    <h2 style="background: #aef; margin: 0">Заголовок</h2>

    <div>А тут - всякий разный текст... <br/>
         ... В две строки!</div>
</div>

В этом документе сейчас все элементы отпозиционированы статически, то есть никак.

Элемент с position: static ещё называют не позиционированным.

position: relative

Относительное позиционирование сдвигает элемент относительно его обычного положения.

Для того, чтобы применить относительное позиционирование, необходимо указать элементу CSS-свойство position: relative и координаты left/right/top/bottom.

Этот стиль сдвинет элемент на 10 пикселей относительно обычной позиции по вертикали:

position: relative;
top: 10px;
<style>
  h2 {
    position: relative;
    top: 10px;
  }
</style>

<div style="background: #fee; width: 500px">
    Заголовок сдвинут на 10px вниз.

    <h2 style="background: #aef; margin: 0;">Заголовок</h2>

    <div>А тут - всякий разный текст... <br/>
         ... В две строки!</div>
</div>

Координаты

Для сдвига можно использовать координаты:

  • top – сдвиг от «обычной» верхней границы
  • bottom – сдвиг от нижней границы
  • left – сдвиг слева
  • right – сдвиг справа

Не будут работать одновременно указанные top и bottom, left и right. Нужно использовать только одну границу из каждой пары.

Возможны отрицательные координаты и координаты, использующие другие единицы измерения. Например, left: 10% сдвинет элемент на 10% его ширины вправо, а left: -10% – влево. При этом часть элемента может оказаться за границей окна:

<style>
  h2 {
    position: relative;
    left: -10%;
  }
</style>

<div style="background: #fee; width: 500px">
    Заголовок сдвинут на 10% влево.

    <h2 style="background: #aef; margin: 0;">Заголовок</h2>

    <div>А тут - всякий разный текст... <br/>
         ... В две строки!</div>
</div>

Свойства left/top не будут работать для position:static. Если их всё же поставить, браузер их проигнорирует. Эти свойства предназначены для работы только с позиционированными элементами.

position: absolute

Синтаксис:

position: absolute;

Абсолютное позиционирование делает две вещи:

  1. Элемент исчезает с того места, где он должен быть и позиционируется заново. Остальные элементы, располагаются так, как будто этого элемента никогда не было.
  2. Координаты top/bottom/left/right для нового местоположения отсчитываются от ближайшего позиционированного родителя, т.е. родителя с позиционированием, отличным от static. Если такого родителя нет – то относительно документа.

Кроме того:

Например, отпозиционируем заголовок в правом-верхнем углу документа:

<style>
  h2 {
    position: absolute;
    right: 0;
    top: 0;
  }
</style>

<div style="background: #fee; width: 500px">
    Заголовок в правом-верхнем углу документа.

    <h2 style="background: #aef; margin: 0;">Заголовок</h2>

    <div>А тут - всякий разный текст... <br/>
         ... В две строки!</div>
</div>

Важное отличие от relative: так как элемент удаляется со своего обычного места, то элементы под ним сдвигаются, занимая освободившееся пространство. Это видно в примере выше: строки идут одна за другой.

Так как при position:absolute размер блока устанавливается по содержимому, то широкий Заголовок «съёжился» до прямоугольника в углу.

Иногда бывает нужно поменять элементу position на absolute, но так, чтобы элементы вокруг не сдвигались. Как правило, это делают, меняя соседей – добавляют margin/padding или вставляют в документ пустой элемент с такими же размерами.

Одновременное указание left/right, top/bottom

В абсолютно позиционированном элементе можно одновременно задавать противоположные границы.

Браузер растянет такой элемент до границ.

<style>
div {
  position: absolute;
  left: 10px; right: 10px; top: 10px; bottom: 10px;
}
</style>
<div style="background:#aef;text-align:center">10px от границ</div>
Внешним блоком является окно

Как растянуть абсолютно позиционированный блок на всю ширину документа?

Первое, что может прийти в голову:

/*+ no-beautify */
div {
  position: absolute;
  left: 0; top: 0; /* в левый-верхний угол */
  width: 100%; height: 100%; /* .. и растянуть */
}

Но это будет работать лишь до тех пор, пока у страницы не появится скроллинг!

Прокрутите вниз ифрейм:

Вы увидите, что голубой фон оканчивается задолго до конца документа.

Дело в том, что в CSS 100% относится к ширине внешнего блока («containing block»). А какой внешний блок имеется в виду здесь, ведь элемент изъят со своего обычного места?

В данном случае им является так называемый («"initial containing block"»), которым является окно, а не документ.

То есть, координаты и ширины вычисляются относительно окна, а не документа.

Может быть, получится так?

/*+ no-beautify */
div {
  position: absolute;
  left: 0; top: 0; /* в левый-верхний угол, и растянуть..  */
  right: 0; bottom: 0; /* ..указанием противоположных границ */
}

С виду логично, но нет, не получится!

Координаты top/right/left/bottom вычисляются относительно окна. Значение bottom: 0 – нижняя граница окна, а не документа, блок растянется до неё. То есть, будет то же самое, что и в предыдущем примере.

position: absolute в позиционированном родителе

Если у элемента есть позиционированный предок, то position: absolute работает относительно него, а не относительно документа.

То есть, достаточно поставить родительскому div позицию relative, даже без координат – и заголовок будет в его правом-верхнем углу, вот так:

<style>
  h2 {
    position: absolute;
    right: 0;
    top: 0;
  }
</style>

<div style="background: #fee; width: 500px; position: relative">
    Заголовок в правом-верхнем углу DIV'а.

    <h2 style="background: #aef; margin: 0;">Заголовок</h2>

    <div>А тут - всякий разный текст... <br/>
         ... В две строки!</div>
</div>

Нужно пользоваться таким позиционированием с осторожностью, т.к оно может перекрыть текст. Этим оно отличается от float.

Сравните:

  • Используем position для размещения элемента управления:

    <button style="position: absolute; right: 10px; opacity: 0.8">
      Кнопка
    </button>
    1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
    1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9

    Часть текста перекрывается. Кнопка более не участвует в потоке.

  • Используем float для размещения элемента управления:

    <button style="float: right; margin-right: 10px; opacity: 0.8;">
      Кнопка
    </button>
    1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
    1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9

    Браузер освобождает место справа, текст перенесён. Кнопка продолжает находиться в потоке, просто сдвинута.

position: fixed

Это подвид абсолютного позиционирования.

Синтаксис:

position: fixed;

Позиционирует объект точно так же, как absolute, но относительно window.

Разница в нескольких словах:

Когда страницу прокручивают, фиксированный элемент остаётся на своём месте и не прокручивается вместе со страницей.

В следующем примере, при прокрутке документа, ссылка #top всегда остаётся на своём месте.

<style>
  #top {
    position: fixed;
    right: 10px;
    top: 10px;
    background: #fee;
  }
</style>

<a href="#" id="top">Наверх (остаётся при прокрутке)</a>

Фиксированное позиционирование.

<p>Текст страницы.. Прокрути меня...</p>
<p>Много строк..</p><p>Много строк..</p>
<p>Много строк..</p><p>Много строк..</p>
<p>Много строк..</p><p>Много строк..</p>
<p>Много строк..</p><p>Много строк..</p>

Итого

Виды позиционирования и их особенности.

static
Иначе называется «без позиционирования». В явном виде задаётся только если надо переопределить другое правило CSS.
relative
Сдвигает элемент относительно текущего места.
  • Противоположные границы left/right (top/bottom) одновременно указать нельзя.
  • Окружающие элементы ведут себя так, как будто элемент не сдвигался.
absolute

Визуально переносит элемент на новое место.

Новое место вычисляется по координатам left/top/right/bottom относительно ближайшего позиционированного родителя. Если такого родителя нет, то им считается окно.

  • Ширина элемента по умолчанию устанавливается по содержимому.
  • Можно указать противоположные границы left/right (top/bottom). Элемент растянется.
  • Окружающие элементы заполняют освободившееся место.
fixed

Подвид абсолютного позиционирования, при котором элемент привязывается к координатам окна, а не документа.

При прокрутке он остаётся на том же месте.

Почитать

CSS-позиционирование по-настоящему глубоко в спецификации Visual Formatting Model, 9.3 и ниже.

Ещё есть хорошее руководство CSS Positioning in 10 steps, которое охватывает основные типы позиционирования.

Задачи

важность: 5

Создайте при помощи HTML/CSS «модальное окно», то есть DIV, который полностью перекрывает документ и находится над ним.

При этом все элементы управления на документе перестают работать, т.к. клики попадают в DIV.

В примере ниже DIV'у дополнительно поставлен цвет фона и прозрачность, чтобы было видно перекрытие:

Браузеры: все основные, IE8+. Должно работать при прокрутке окна (проверьте).

Открыть песочницу для задачи.

Если использовать position: absolute, то DIV не растянется на всю высоту документа, т.к. координаты вычисляются относительно окна.

Можно, конечно, узнать эту высоту при помощи JavaScript, но CSS даёт более удобный способ. Будем использовать position:fixed:

Стиль:

#box {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 999;
}

Свойство z-index должно превосходить все другие элементы управления, чтобы они перекрывались.

Открыть решение в песочнице.

Карта учебника

Комментарии вернулись :)

перед тем как писать…
  • Если вам кажется, что в статье что-то не так - вместо комментария напишите на GitHub.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.