Позиционирование элементов с помощью свойства position
Зачастую существуют ситуации, когда необходимо расположить блок поверх другого блока. Яркий пример можно увидеть в интернет-магазинах, когда метки "New" или "0-0-24" находятся по вверх изображения.
Для решения такого рода задач используют комбинации свойств: position, top, right, bottom, left и z-index.
И для того, чтобы мы разобраться как работают свойства вместе, сначала нужно рассмотреть их по отдельности.
position
Свойство position определяет точку относительно, которой браузер будет рассчитывает позицию элемента. Существуют следующие варианты:
- статическое (static);
- относительное (relative);
- абсолютное (absolute);
- фиксированное (fixed);
left, right, top и bottom
Группа свойств, с помощью которых можно сдвинуть элемент как по горизонтальной оси(left и right), так и по вертикальной(top и bottom). Свойство top сдвигает элемент вниз, right — влево, bottom — вверх, left — вправо.
z-index
Свойство, которое задает приоритет блоков при наложении их друг на друга.
Вот и все. У нас есть все требуемые знания для того, чтобы разобрать как свойства работают вместе.
Относительное позиционирование
При относительном позиционировании браузер рассчитывает позицию элемента относительно первоначального местоположения его левого верхнего угла. Давай создадим один блок, в котором поместим два квадрата.
<div class="parent">
<div class="block block1">Первый блок</div>
<div class="block block2">Второй блок</div>
</div>
.parent{
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
position: relative;
}
.block1{
background-color: tomato;
}
.block2{
background-color: green;
}
Так как элементы являются блочными, то они расположились друг под другом. А теперь, используя свойство left, подвинем первый блок вправо на 100px, а второй на 50px.
.block1{
left: 100px;
background-color: tomato;
}
.block2{
left: 50px;
background-color: green;
}
Браузер сдвинул элементы вправо относительно левого верхнего угла их начального местоположения.
Сделаем еще один эксперимент, в котором мы подвинем зеленый блок выше 50 пикселей.
.block2{
bottom: 50px;
left: 50px;
background-color: green;
}
Мы видим, что элемент сдвинулся вверх все также относительно левого верхнего угла своей начальной позиции.
Но также, из эксперимента можно подчеркнуть то, что при относительном позиционировании элементы могут наложиться друг на друга. Но, если посмотреть на высоту родителя, то можно заметить, что она не меняется.
В следующем примере мы уберем свойство width у квадратов.
После того, как мы отключили свойство width ширина блоков снова стала равняться ширине родителя. Но, из-за того, что мы сдвинули элементы, используя свойство left, они вышли за пределы своего родителя.
Но это не все полезные выводы из этого эксперимента. Если посмотреть на свойство display, то мы увидим, что оно имеет значение block. Поэтому мы можем сделать вывод, что значение relative никак не влияет на свойство display у элементов.
Также проверим, сохранятся ли значение inline строчные элементы. Для этого заменим теги следующим образом и у второго квадрата уберем bottom: 50px.
<div class="parent">
<span class="block block1">Первый блок</span>
<span class="block block2">Второй блок</span>
</div>
Элементы сохранили значение inline, соответственно, и свойства.
Подведем итоги. Когда мы используем position: relative, то элемент начинает обладать следующими свойствами:
- координаты элементы рассчитывают относительно левого верхнего угла начального местоположения
- у элементов не меняются значения свойства display, и поэтому сохраняют свои свойства
- высота родительского блока рассчитывается и сохраняется до момента применения координат элементов
- при отсутствии координат элементы располагаются согласно их свойств.
Абсолютное позиционирование
Изучение абсолютного позиционирования мы начнем сразу с примера из раздела "Относительное позиционирование". Только заменим значение свойства position у элемента .block с relative на absolute.
<div class="parent">
<div class="block block1">Первый блок</div>
<div class="block block2">Второй блок</div>
</div>
.parent{
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
position: absolute;
}
.block1{
background-color: tomato;
}
.block2{
background-color: green;
}
Сразу бросается в глаза, что родительский блок схлопнулся. Посмотрим на свойство height у элемента.
0! Опять мы видим, что родительский блок не видит свои дочерние элементы. Ранее мы сталкивались с похожим поведением при float позиционировании, но здесь есть одно ключевое отличие. Абсолютные блоки полностью выпадают из потока, и поэтому они невидимы ни для элементов, ни для текста.
Также они прижались к левому углу родительского блока. Но давай добавим padding для него и посмотрим, где будут располагаться дочерние элементы.
.parent{
border: 2px solid black;
padding: 20px;
}
Блоки сдвинулись на 20 пикселей по вертикальной и горизонтальной оси. Получается, что когда мы указываем absolute, то элемент прижимается к левому верхнему углу контентной части родителя.
Теперь попробуем добавить координаты для блоков. Первому элементу зададим top: 0, а второму right: 0.
.block1{
background-color: tomato;
top: 0;
}
.block2{
background-color: green;
right: 0;
}
Мы видим, что первый блок прижался к верху области просмотра браузра (вьюпорту) по оси Y, но остался на том же расстоянии что и раньше по оси X. А вот второй блок, напротив, сдвинулся по оси X к границе вьюпорта, а по оси Y остался на месте.
Прежде чем объяснить, почему так произошло, мы сделаем еще один эксперимент. Добавим к родительскому блоку свойство position: relative.
.parent{
position: relative;
border: 2px solid black;
padding: 20px;
}
Ты заметил, что блоки теперь позиционируется от родителя, а не от вьюпорта? Проясню, почему так произошло.
Когда мы используем absolute, то браузер рассчитывает позицию элемента относительно границ родительского элемента с нестатическим типом позиционирования (relative, absolute, fixed). Но! Если такого элемента нет, то относительно границ вьюпорта.
Например, в первом примере браузер вывел блоки следующим образом:
В этом случае он не нашел родительский элемент с нестатическим типом позиционирования, поэтому позиционировал блоки относительно границ вьюпорта. У первого блока была задана координата по оси Y (top: 0), поэтому он прижался к верхнему краю. А второму блоку мы задали значение по оси X (right: 0), поэтому браузер прижал элемент к правому краю.
Но после того, как мы задали position: relative для родительского блока, то браузер нашел элемент с нестатическим позиционированием и стал рассчитывать значения относительно него.
Теперь попробуем задать координаты для блоков по двум осям. Первый мы расположим в левом верхнем углу родителя, а второй в правом нижнем.
.block1{
background-color: tomato;
top: 0;
left: 0;
}
.block2{
background-color: green;
bottom: 0;
right: 0;
}
Как видим, первый блок отобразился в левом верхнем углу родителя, но его нижняя часть вышла за его пределы. Наверно тебе кажется это странным, но на самом деле это абсолютно логично.
Когда мы написали left: 0 и top: 0, то сказали браузеру прижать левый верхний угол к левому верхнему углу родителя. Но из-за того, что он выпал из потока, то его высота не влияет на родителя, поэтому он вышел за его пределы. Тоже самое произошло и со вторым, только с одним отличием. Из-за того, что мы с помощью координат right: 0 и bottom: 0 прижали блок к низу родителя, он был обрезан сверху.
Но это еще не все особенности абсолютного позиционирования. Ранее в примерах мы добавляли absolute для блочных элементов. Но давай мы заменим теги <div> на <span>.
<div class="parent">
<span class="block block1">Первый блок</span>
<span class="block block2">Второй блок</span>
</div>
.parent{
position: relative;
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
position: absolute;
}
.block1{
background-color: tomato;
top: 0;
left: 0;
}
.block2{
background-color: green;
top: 0;
right: 0;
}
Мы видим, что внешне результат не отличается от того, что был с блочными элементами. Но почему свойства width и height сработали?
Дело в том, что после того как мы указали absolute, то браузер сделал эти элементы блочными. Это мы можем проверить в веб-инспекторе.
Если мы укажем display со значением inline или inline-block, то бразуер проигнорирует их и оставит block.
В предыдущем эксперименте мы задавали размеры блока, а теперь пусть браузер сам сделает это.
<div class="parent">
<div class="block block1">Первый блок</div>
<div class="block block2">Второй блок</div>
</div>
.parent{
position: relative;
border: 2px solid black;
}
.block{
position: absolute;
}
.block1{
background-color: tomato;
top: 0;
left: 0;
}
.block2{
background-color: green;
top: 0;
right: 0;
}
Как мы видим размеры рассчитываются по контенту, и не важно то, что элементы являются блочными.
Такое поведение вызвано тем, что блоки уже не находятся в потоке, соответственно не могут растягиваться по ширине родителя. Но и без размеров они остаться не могут, следовательно браузер остается только рассчитать их по контенту.
Подведем итоги. Когда мы используем position: absolute, то элемент начинает обладать следующими свойствами:
- он становится блочным
- полностью выпадает из потока
- размеры элемента рассчитываются по размеру контента
- при отсутствии координат элемент прижимается к левому верхнему углу контентной области родителя
- координаты рассчитываются от границ нестатического элемента, и если такого нет, то от границ вьюпорта
Fixed
Фиксированное позиционирование получило свое название из-за того, что элемент при данном типе "фиксируется" на одном месте даже при прокрутке страницы. Например, различные фиксированное меню или кнопки "Наверх" являются практическим примером этого типа.
Элементы с фиксированным позиционированием очень похожи на абсолютные и имеют несколько общих свойств:
- элемент становится блочным и это нельзя изменить
- элемент полностью выпадает из потока
- размеры элемента рассчитываются по размеру контента
- при отсутствии координат элемент прижимается к левому верхнему углу контентной области родителя
Но элемент с фиксированным позиционирование имеет очень важное отличие. И на примере разберем его. Давай попробуем добавить position: fixed и координаты для квадратов.
<div class="parent">
<div class="block block1">Первый блок</div>
<div class="block block2">Второй блок</div>
</div>
.parent{
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
position: fixed;
}
.block1{
background-color: tomato;
top: 0;
left: 0;
}
.block2{
background-color: green;
bottom: 0;
right: 0;
}
И сразу же добавим position: relative к родительскому блоку:
.parent{
position: relative;
border: 2px solid black;
}
Как видишь, результаты экспериментов одинаковые, и поэтому, мы можем убедиться в том, что при фиксированном позиционировании точки расчета координат всегда будут начинаться от границ вьюпорта.
Отрицательные значения для свойств top, left, bottom, right
Ранее мы задавали только положительные значения для определения координат. Но нам также доступны и отрицательные значения.
Вернемся к примеру с абсолютном позиционированием и добавим для координат отрицательные значения.
<div class="parent">
<div class="block block1">Первый блок</div>
<div class="block block2">Второй блок</div>
</div>
.parent{
position: relative;
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
position: absolute;
top: -50px;
}
.block1{
background-color: tomato;
left: 0;
}
.block2{
background-color: green;
right: 0;
}
В итоге у нас получилось то, что элементы сдвинулись вверх на 50px, т.е используя отрицательное значение для свойства top, браузер переместил элементы в противоположное направление.
Точно также браузер поступит и для свойств left, right, bottom, т.е для первого при отрицательном значении элемент сдвигается влево, при втором — вправо, а при третьем — вниз.
z-index
Давай вернемся к примеру с абсолютным позиционированием.
<div class="parent">
<span class="block block1">Первый блок</span>
<span class="block block2">Второй блок</span>
</div>
.parent{
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
background: red;
position: absolute;
}
.block1{
height: 150px;
}
.block2{
background: green;
}
Почему же второй блок располагается по вверх первого? Дело в том, что в HTML он находится ниже чем первый, поэтому браузер сначала отобразил первый элемент, а потом второй.
Но это мы можем изменить. Для этого существует свойство z-index. В качестве значения оно принимает число, которое определяет порядок.
К примеру, нам нужно, чтобы первый блок был выше. Для этого ему нужно указать z-index больше чем у второго. А так как у второго его нет, то для первого достаточно установить значение 1.
.parent{
border: 2px solid black;
}
.block{
width: 100px;
height: 100px;
background: red;
position: absolute;
}
.block1{
height: 150px;
z-index: 1;
}
.block2{
background: green;
}
Но со свойством z-index есть один нюанс. Оно работает только для элементов, у которых значение свойства position отличается от static.