Позиционирование
Обновлено
06.11.2023Просмотров
327Время прочтения
30 мин.Сложность
Говоря о позиционировании, следует рассказать о «нормальном потоке» документа. Когда вы добавили теги в html файл и не добавляли никакие стили, вы видите свою веб-страницу, где теги идут друг за другом или в одну строчку — в зависимости от их свойства display, размера и пр. Но в любом случае все они находятся там, где и должны находиться с учётом их положения в разметке и размера\контента других тегов. Это и называется «нормальным потоком». Также это называется статичным позиционированием (position: static). Все теги на веб странице по умолчанию позиционированы статично!
На скриншоте ниже вы видите «нормальный поток», теги в разметке и на странице располагаются друг за другом, учитывая взаимные размеры и содержимое.
Впрочем, вы к этому уже должно быть привыкли: во всех прежних примерах все теги располагались статично.
Прежде чем мы станем изучать другие виды позиционирования, мы должны вспомнить такие понятия, как вложенность тегов, теги-предки и теги-потомки.
Вложенными являются любые теги, вложенные в другой, на любом уровне. То есть абсолютно все теги вложены в <html>. Также эти вложенные теги являются потомками для этого тега, а он является их предком. Разумеется, предок может быть не один, их может быть несколько, на разных уровнях.
На скриншоте <main> является предком для всех прочих тегов, вложенных в него. И все вложенные в него теги являются его потомками. Вспомните и осознайте заново, если требуется, эти понятия. Для темы CSS позиционирования они предельно важны.
POSITION: RELATIVE
Это называется относительным позиционированием. Эта модель наиболее легка для понимания. Её суть, если передать простыми словами, заключается в следующем: элемент сохраняет своё положение в нормальном потоке документа, но при этом визуально смещается относительно своего первоначального положения в определённую сторону (как укажет разработчик).
Рассмотрим прежний пример, где мы имеем два квадрата и небольшой текст.
Прежде все наши элементы находились в нормальном потоке. Для красного квадрата мы указали position: relative. Но этого ещё недостаточно для того, чтобы увидеть какие-либо изменения. Далее необходимо при помощи свойств top, left, right, bottom указать размер смещения относительно определённой стороны. Так, мы указали top: 50px и left: 40px и наш квадрат визуально сдвинулся на 50 пикселей от своего верха и на 40 пикселей от своего левого края.
Важным обстоятельством является то, что пространство, которое занимал элемент, осталось зарезервировано за ним. По большому счёту, элемент так же остался в нормальном потоке, но сдвинулся визуально.
Вышеуказанные свойства top, left, right, bottom работают с любым позиционированием, кроме статичного, пожалуйста, запомните это! При этом свойства top, left являются приоритетными над right, bottom. В случае, если вы одновременно укажете и те, и другие стороны, именно top, left будут работать, а right, bottom будут проигнорированы:
Это правило, однако, работает только в случае, если top, left указаны как числовые значения. Если вы укажете например top: unset или top: auto, свойство bottom будет работать в полную меру.
Не следует заблуждаться по поводу работы свойств, определяющих смещение элемента. Название свойства не определяет направление, в котором элемент будет смещён. Название только определяет сторону элемента, относительно которой задаётся смещение. При этом направление может быть как отрицательным, так и положительным. Простейшую схему направления смещений вы видите на скриншоте ниже:
Так, если мы хотим сместить элемент довольно сильно вправо, нам будет удобнее воспользоваться отрицательным значением right: -40px и т.д.
Значение в px, pt, %, em, rem и др. величинах | определяет величину смещения с указанной стороны. При указании % значение рассчитывается относительно высоты (top,bottom) или ширины (left,right) родительского элемента. Может принимать отрицательное значение |
auto | значение по умолчанию. При указании для какой-либо стороны будет означать, что элемент в позиционировании будет ориентироваться на противоположную сторону. Например, при left: auto элемент будет ориентироваться на значение right. Если оно не задано или тоже равно auto, то элемент не будет смещён по горизонтали |
initial | свойство принимает значение по умолчанию |
inherit | наследует значение от родителя |
unset | значение не указано. Поскольку все свойства ненаследуемые, будет установлено значение по умолчанию, то есть auto |
POSITION: ABSOLUTE
Абсолютное позиционирование во многом отличается от относительного. Такой элемент вырывается из нормального потока документа и остаётся сам по себе, никак не влияя больше на другие элементы (не двигая их своими размерами, маржей и пр.). Также другие элементы не могут повлиять на такой элемент. Ширина и высота абсолютно позиционированного элемента (если явно не заданы) уменьшаются до минимума, чтобы только вместить его содержимое.
Пример отображения абсолютно позиционированного элемента представлен ниже:
Красный квадрат находится в элементе с классом container, там же присутствует текст. Хотя текст расположен в разметке ниже, он отображается на странице так, будто нашего box вообще нет в элементе. Это демонстрация того, о чём было сказано выше: абсолютно позиционированный элемент вырывается из нормального потока. Именно это и произошло, красный квадрат просто «повис» сверху на странице над другими элементами, а место, которое он занимал, было предоставлено другим элементам согласно нормальному потоку. Теперь, какую бы мы маржу и размеры не задали этому квадрату, он не будет влиять ни на какие другие элементы, равно как и никакие другие не будут влиять на него.
Для абсолютно позиционированного элемента, а также для всех прочих моделей позиционирования, которые мы будем дальше в уроке изучать, крайне важно значение свойства position у его предков. Вы на скриншоте видите, что для квадрата заданы свойства top, left, но может возникнуть вопрос — относительно чего они рассчитываются? Absolute будет рассчитываться не относительно первоначального положения элемента, а относительно ближайшего предка с любым значением position, отличным от static. Так, в нашем примере container имеет position: relative, поэтому положение квадрата будет отсчитываться от его верхнего левого края. Напомним, что координатная ось браузера и всех элементов начинается в верхнем левом углу, горизонтальная ось уходит вправо, вертикальная вниз. Так, мы сдвинули квадрат на 40px вниз относительно верхнего края container и на 100px относительно его левого края.
Думаю, поведение абсолютно позиционированного элемента вам теперь становится понятным: он ищет ближайшего предка с любым position, кроме static, а это значения relative, absolute, fixed, sticky. Так, элемент будет подниматься выше и выше по структуре документа, пока не найдёт предка с таким подходящим ему значением. В случае, если такого предка не будет совсем, то исходной точкой, от которой будет отсчитываться смещение элемента, будет верхний левый угол отображаемой веб страницы:
Как видите, мы указали для container position: static, так что наш квадрат не имеет родителя с подходящим position. Кроме того, для наглядности мы задали маржу для body, так что теперь явно видно, что квадрат позиционируется относительно окна просмотра, но не относительно body и не относительно тега html.
Такое поведение абсолютно позиционированных элементов при отсутствии подходящих предков это не стандарт CSS, а поведение браузера. Хотя чаще всего это работает именно так, поведение в некоторых браузерах может незначительно отличаться.
Как уже было сказано, абсолютно позиционированный элемент ищет ближайшего предка со значением relative, absolute, fixed, sticky. Чаще всего вы будете в работе располагать абсолютные элементы внутри относительно позиционированных. Однако вы можете располагать абсолютные и внутри абсолютных, иногда это будет очень удобно:
Как видите, container у нас остался relative, а вот оба квадрата, большой и маленький, абсолютно позиционированы. Красный ориентируется на container, а зелёный — на красный.
POSITION: FIXED
Это позиционирование довольно легко для понимания. Элемент фиксируется в области просмотра браузера и находится там всегда. Ориентирование для свойства top, bottom, left, right происходит от верхнего левого угла окна просмотра. Разумеется, при таком позиционировании элемент вырывается из нормального потока документа и не занимает никакого места, а также не реагирует на другие элементы. Подобно absolute, ширина фиксированного элемента, если явно не задана, стремится к нулю, т.е. элемент станет минимальным, чтобы только вместить контент.
На скриншоте мы имеем параграф с длинным текстом, который создаёт скролл на странице. Страница уже прокручена, но красный квадрат всё время находится в одном и том же месте. Если мы будет дальше прокручивать страницу, он будет «ехать» дальше вниз. Его смещение задано относительно окна просмотра браузера. top: 10% означает смещение на 10% от высоты окна (родителем в данном случае выступает окно просмотра), а left: 10vw означает смещение на 10 viewport width. Хотя мы ещё не изучали величины измерения, вы уже можете знать, что вся ширина экрана устройства равняется 100vw, а вся высота 100vh. Соответственно 10vw будет означать десятую часть от ширины экрана. Для ширины это то же самое, что и 10%, а вот для высоты 10% и 10vh не всегда будут работать одинаково. Однако это тема для урока про единицы измерения. Сейчас же стоит только сказать, что для фиксированных и абсолютных элементов при указании свойств top, bottom, height следует пользоваться процентами %, а не vh. Забежим немного вперёд с объяснениями: это связано с динамической панелью навигации мобильных браузеров Chrome, Opera и других, которая появляется при прокрутке страницы вверх:
На картинках слева вы видите панель навигации мобильного браузера Chrome, которая появляется только при прокрутке страницы вверх. При обычном скролле вниз эта панель скрывается. Такой функционал весьма удобен, однако он влияет на высоту страницы. В результате она постоянно изменяется. Одновременно с этим единицы vh НЕ изменяются динамически. Они определяются по изначальной высоте страницы, а изначальная высота страницы рассчитывается с учётом показанной верхней панели, которая затем исчезает. Так, при работе с 100vh мы в итоге при скролле вниз получим высоту страницы 100vh + высота панели (а эту высоту мы не можем узнать на веб странице ни в CSS, ни в JS). В то же время высота 100% для абсолютных и фиксированных элементов учитывает показанную\скрытую мобильную панель, то есть эти 100% динамические, поэтому они для нас удобнее, чем vh. Всё это, в общем-то, уже тонкости, про которые сейчас вы узнаёте для ознакомления. Постарайтесь вспомнить об этом, когда столкнётесь в работе с проблемой высоты блоков на мобильных.
Приоритет свойств top, bottom, left, right такой же, как и для position: absolute. Если указаны числовые значения top, left, то именно они будут приоритетными над bottom, right. Отрицательные значения тоже допускаются. В таком случае элемент будет фактически уезжать за пределы окна просмотра браузера и не будет виден пользователю.
Как вы помните, абсолютный элемент будет ориентироваться на предка с relative, absolute, fixed, sticky. Поэтому вы можете удобно разместить кнопку закрытия модального окна внутри него, ориентировав само окно фиксированно, а кнопку абсолютно. Это является частой и неплохой практикой:
POSITION: STICKY
Последним видом позиционирования является «липкое» позиционирование. Оно самое прогрессивное и необычное из всех. Суть его заключается в том, что элемент становится на время фиксированным, при прокрутке страницы до определённого места, а затем перестаёт быть липким и располагается там, где находился в последний момент прокрутки. Объяснить это поведение словами было бы довольно сложно, поэтому смотрите пример:
В примере у нас в container находятся несколько абзацев с длинным текстом, а между ними box, для которого определено липкое позиционирование. Также указано свойство top: 5vw, и это означает, что элемент прилипает тогда, когда от окна просмотра до его верха остаётся расстояние в 5vw. Мы видим, что при прокрутке до box в какой-то момент он начинает «ехать» вместе с прокруткой, а затем останавливается в том месте, где оказался в последний момент. Это и есть липкое позиционирование. Важно здесь то, что липкий элемент перемещается только в пределах высоты своего родителя, поэтому box перемещается вниз в пределах container, а затем, когда достигает его низа, прекращает перемещаться. Обращайте внимание на высоту родителя sticky-элемента, начинающие разработчики довольно часто совершают ошибку, оставляя высоту родителя недостаточной для работы липкого позиционирования.
Также важным отличием от fixed, absolute является то, что sticky-элемент вырывается из нормального потока, но только наполовину: место, на котором он изначально находился, резервируется за ним (как при position: relative). Когда элемент становится липким, разумеется, он больше не реагирует на другие элементы. Ширина и высота sticky-элемента остаётся такой же, какой и была при статичном позиционировании элемента, т.е. блочный элемент будет растягиваться на всю ширину родителя, строчный и блочно-строчный будут занимать ширину, необходимую для размещения контента.
Position: sticky часто применяется на сайте, когда у нас есть область контента и боковая панель небольшой высоты. При прокрутке страницы, если панель будет статичной, на её месте будет незанятое пространство, что во-первых не слишком красиво, а во-вторых неудобно, если пользователь захочет воспользоваться боковой панелью. Ведь ему придётся прокручивать страницу обратно вверх. Sticky-панель решает обе эти проблемы, панель будет в зоне видимости столько, сколько нужно.
Пример работы липкого элемента — это любое объявление на сайте avito, блок с ценой, телефоном и пр. является липким и будет ехать вместе с прокруткой до самого низа своего родителя:
static | значение по умолчанию. Элемент находится в нормальном потоке, т.е. там, где и должен располагаться с учётом его размера, контента, отступов, а также с учётом положения других элементов. Свойства top, bottom, left, right игнорируются |
relative | элемент формально остаётся на своём месте в нормальном потоке, но может визуально смещаться при помощи свойств top, bottom, left, right. Зарезервированное место на веб странице за элементом при этом сохраняется |
absolute | элемент вырывается из нормального потока и больше не занимает место, не реагирует на другие элементы. Ширина элемента при этом стремится к минимуму. Ориентирование для свойств top, bottom, left, right происходит от ближайшего предка с любым позиционированием, кроме статичного |
fixed | элемент вырывается из нормального потока и «прилипает» к определённому положению в области просмотра браузера. Элемент больше не занимает место на странице, не реагирует на другие элементы. Ширина элемента при этом стремится к минимуму. Ориентирование для свойств top, bottom, left, right происходит от верхнего левого угла окна просмотра браузера |
sticky | элемент располагается на своём месте на странице, как будто находится в нормальном потоке. При прокрутке страницы до указанного для элемента значения свойства top элемент становится фиксированным и ведёт себя так до конца высоты родительского элемента |
Z-INDEX
Различные виды позиционирования это ещё не всё, что вам необходимо знать по этой теме. В ситуации, когда у нас есть несколько нестатичных блоков, они должны отображаться в каком-то порядке друг за другом или друг перед другом. За порядок отображения блоков отвечает CSS свойство z-index, которое указывается непосредственно для каждого блока и имеет числовое значение. Оно может быть сколько угодно маленьким (-10000 и меньше) и сколь угодно большим (999999). Элемент с большим индексом отображается впереди, с меньшим позади.
По умолчанию z-index у всех элементов равен auto, что на практике равняется значению 0. Это означает, что элементы будут отображаться с таким приоритетом, как они расположены в разметке. Нижестоящие элементы будут располагаться впереди, вышестоящие — позади:
Вы видите три одинаковых box, позиционированных абсолютно. По так называемой оси Z (ближе-дальше) они расположены в том порядке, в каком находятся в разметке, красный выше в разметке и на самом дальнем плане, синий следующий в разметке и впереди красного на странице, и т.д.
Это поведение элементов по умолчанию, которое мы можем переопределить при помощи z-index:
Указав для красного блока индекс 1, мы дали ему приоритет в отображении и он стал отображаться ближе к пользователю, чем другие блоки. Напомним, по умолчанию все элементы имеют значение auto, что равняется 0. Поэтому красный имеет индекс выше и отображается впереди.
auto | Значение по умолчанию. Элемент не создаёт локального контекста наложения (см. ниже). Порядок наложения блока будет равен 0 |
целое число | порядок наложения блока в текущем контексте наложения. Чем выше индекс — тем ближе к пользователю отображается блок. Элемент создаёт новый контекст наложения |
inherit | наследует значение от родителя |
Это далеко не исчерпывающая информация по расположению элементов по оси Z, однако достаточная на данный момент для начинающих. Подробнее о контекстах наложения и работе z-index пойдёт речь в отдельном уроке