Сегодня мы будем говорить о позиционировании элементов на странице. Как вы можете догадаться, в CSS есть свойство, которое ровно так и называется position. По-умолчанию все элементы на странице имеют position: static. Вот список какие ещё значения position бывают.
- static
- relative
- absolute
- fixed
- sticky
Первый тип позиционирования – относительное. Определение (перевод отсюда)
Положение бокса вычисляется относительно нормального потока (это называется положение в нормальном потоке). Затем бокс смещается относительно своей нормальной позиции и во всех случаях, включая элементы таблиц, не влияет на позиционирование следующих боксов. Когда бокс B относительно спозиционирован, то положение его бокса считается как будто бы смещения не было. Эффект позиционирования элементов таблиц определяется следующим образом:
- table-row-group, table-header-group, table-footer-group и table-row смещаются относительно своей нормальной позиции в таблице. Если ячейка таблицы растягивается на несколько строк, то только ячейки, находящиеся в соответствующих относительно спозиционированных строках имеют смещение (если что у меня не получилось заставить это работать).
- table-column-group, table-column не смещаются относительно соответствующей колонки и по факту никакого эффекта от position: relative не происходит
- table-caption и table-cell смещаются относительно нормального положения в таблиец. Если ячейка объединяет несколько, то все они смещаются относительно своего нормального положения.
Относительно спозиционированный блок создаёт новый содержащий блок – это самое распостранное использование данного значения.
Смещение регулируется свойствами top, left, right, bottom
. Красивого свойства для задания всех значений разом нет. Относительные значения считаются от размеров содержащего блока. Задание данных свойств никак не изменяет размеры самого блока.
По-умолчанию, когда left/right auto, то они равны 0. Когда кто-то один из left/right auto, то по факту выполняется равенство left = -right. Если же задать и left, и right то одно из свойств просто игнорируется. Какое именно зависит от свойства direction. ltr – right, rtl – left.
Примерно такой же алгоритм работы у top/bottom, за исключением двух но. Во-первых, если содержащему блоку не задана высота, то top/bottom заданные в процентах всегда будут равны auto, т.е 0. И второе, что нет свойства, которое бы меняло приоритеты, при задании top/bottom вместе. Т.е top всегда побеждает bottom.
Позиция и размеры бокса элементов в некоторых случаях считаются относительно некоторого прямоугольника, который называется «содержащим блоком» элемента.
Содержащий блок для static, relative и sticky элементов определяется следующим образом (ссылка):
- Для корневых элементов это премоугольник размерами с вьюпорт, который привяз к размерам видимой области окна для непрерывных страниц или страницы для листаемых источников. Такой содержащий блок называется стартовым (инициализационным). Значения свойств 'direction' и 'block-progression' в таком случае будут такими же как и у корневого
- В остальных случаях содержащий блок это прямоугольник, который формируется границами контентной области ближайшего родителя блочного уровня. В том числе это может быть анонимный бокс.
Содержащий блок у fixed элементов – это всегда viewport. Во всех случаях.
У абсолютно спозиционированных элементов содержащим блоком является первый родитель, значение свойства position которого отлично от static. При этом:
- Если этот родитель блочного уровня, то прямоугольник содержащего блока определяется padding'овыми границами
- Если этот родитель строчного уровня, то:
- Если direction ltr, то левая верхняя граница содержащего блока будет равна левой верхней границе первого элемента внутри абсолютного блока, а нижняя правая граница будет равна нижней правой границе последнего ребенка абсолютно спозиционированного блока (грубо говоря, высота блока определяется под контент, ширина – максимум из ширин блоков внутри)
- При direction rtl, всё точно так же, только уже рост блока идёт от правой границы.
- Во всех остальных случаях берется стартовый блок (чаще всего это viewport).
При постраничной разметке важно заметить, что абсолютно спозиционированный блок позиционируется игнорируя размеры страниц и разрывы между ними, т.е может быть размазан на несколько страниц разом.
Примеры
- Блочный блок + position: relative в пикселах
- Инлайн блок + position: relative в пикселах
- Блочный блок + position: relative в процентах
- Инлайн блок + position: relative в процентах
Блок со значением absolute переходит в режим абсолютного позиционирования. При таком позиционировании блок выводится из потока, при этом сам блок образует новый содержащий блок.
У абсолютно позиционированного блока есть ограничение сверху на размер, оно выражается формулой:
left + margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right + right = width содержащего блока
Вот таблица рассчёта параметров, ✔ – означает auto значение данного параметра. Примечание, предполгается, что direction равен ltr.
left | width | right | margin-left | margin-right | Результат |
---|---|---|---|---|---|
✔ | ✔ | ✔ | любое | любое | авто margin -> 0 пример / иначе margin-left побеждает margin-right пример, left -> то же как static, width -> под контент, right -> вычисляется по формуле |
✘ | ✘ | ✘ | ✔ | ✘ | margin-left -> оставшееся место (вычисляется), пример |
✘ | ✘ | ✘ | ✘ | ✔ | margin-right -> оставшееся место (вычисляется), пример |
✘ | ✘ | ✘ | ✔ | ✔ | свободное место делится пополам между margin'ами, пример |
✘ | ✘ | ✘ | ✘ | ✘ | right -> auto, пример |
✔ | ✘ | ✔ | любое | любое | margin -> 0, left -> то же как static, width -> сколько указано, right -> вычисляется, пример |
✔ | ✔ | ✘ | любое | любое | margin -> 0, left -> вычисляется, width -> под контент, right -> сколько указано, пример |
✘ | ✔ | ✔ | любое | любое | margin -> 0, left -> сколько указано, width -> под контент, right -> вычисляется, пример |
✘ | ✘ | ✔ | любое | любое | margin -> 0, right вычисляется по формуле, пример |
✘ | ✔ | ✘ | любое | любое | margin -> 0, width вычисляется по формуле, пример |
✔ | ✘ | ✘ | любое | любое | margin -> 0, left вычисляется по формуле, пример |
Если ширина и высота имеют вычисленные значения auto, при этом у элемента есть внутренняя ширина (например у картинок), то используется внутреннее значение.
Если ширина и высота имеют значение auto, при этом у элемента нет внутренней ширины, но есть внутренняя высота и пропорция; или если ширина auto, высота имеет какое-то значение отличное от auto и у элемента есть внутреннее значение пропорции, то ширина вычисляется по формуле:
(высота) * (внутренняя пропорция)
Если ширина и высота auto, у элемента есть внутренняя пропорция, но нет внутренней ширины или высоты и ширина содержащего блока не зависит от ширины замещаемого элемента (я эту часть фразы не могу смоделировать). Тогда значение ширины вычисляется из уравнения, используемого для блочных, незамещаемых элементов в нормальном потоке.
Во всех остальных случаях когда ширина auto и у элемента есть внутренняя ширина, то используется она.
Если же ширина auto и ничего выше не подходит, то ширина элемента просто становится 300px. Если 300px – это больше ширины экрана, тогда девайс должен выставить такое значение, которое будет назначено ширине максимального большого прямоугольника с пропорциями 2:1, который вмещается в экран девайса.
После вычисления ширины для позиционирования элемента применяются следующие правила:
- Если left и right auto и direction статического родителя ltr, то left будет равно left статического контейнера, а right вычисляется. При rtl соответственно наоборот.
- Если left auto, right задано, то если margin-left и margin-right auto, то они автоматически равны 0, а затем вычисляется left
- То же самое что и в 2, но наоборот при left не auto.
- Если margin-left и margin-right всё ещё auto, то в уравнение вводится доп.условие, что вычисленные значения margin-left/margin-right должны быть одинаковыми. Это не относится к ситуации, когда при этом вычисленные значения будут отрицательными, тогда при ltr direction содержащего блока margin-left будет равен 0 и вычисляется margin-right. Для rtl всё наоборот
- Если всё ещё есть auto значения, то нужно вычислить их по уравнению для незамещаемых элементов
- Если значений больше, чем можно применить, то нужно проигнорировать значение свойства left (при ltr).
Здесь правила похожи, есть формула:
top + margin-top + border-top-width + padding-top + height + padding-bottom + border-bottom-width + margin-bottom + bottom = высота содержащего блока
Если top, bottom и height имеют значение auto. То auto значения margin-top/bottom становятся 0. Затем top присваивается значение top в статической позиции, и затем применяется правило 3, ниже.
Если наоборот из тройки ни одно не имеет значения auto, то для разрешения auto margin-top/bottom вводится доп.ограничение, что их значения должны быть равны. Если при этом значений больше чем нужно, то игнорируется значение bottom.
Во всех остальных случаях auto margin-top/bottom присваивается значение 0 и выбирается одно из следующих правил:
- If top and height are auto and bottom is not auto, then the height is based on the Auto heights for block formatting context roots, and solve for top.
- If top and bottom are auto and height is not auto, then set top to the static position, then solve for bottom.
- If height and bottom are auto and top is not auto, then the height is based on the Auto heights for block formatting context roots, and solve for bottom.
- If top is auto, height and bottom are not auto, then solve for top.
- If height is auto, top and bottom are not auto, then solve for height.
- If bottom is auto, top and height are not auto, then solve for bottom.
Плавающий или флоат (транскрипция float) блок – это блок, который сдвигается влево или вправо на текущей строке. Наиболее интересная характеристика таких блоков – это то что контент выстраивает вдоль границы такого блока.
Плавающий блок сдвигается до границы содержащего блока или до внешней границы другого плавающего блока, в рамках строки (в английском варианте используется термин line box) верхняя граница плавающего блока выравнивается с верхней границей строки (line box).
Если в строке не достаточно места, то блок смещается вниз до тех пор, пока не находит места для себя. При этом float блоки в порядке объявления в DOM'е формируют отдельный float поток и при выборе места для следующего блока браузер изначально смотрит на позицию последнего блока во float потоке.
Для более понятного понимания float'ов можно использовать аналогию с тетрисом, в котором при размещении блока браузер руководствуется правилом: вниз и влево. Простой пример