Прокрутить к контенту ↓


Вертикальная перестановка блоков средствами CSS

Краткое описание
Кроссбраузерный способ полноценной вертикальной перестановки блоков произвольной высоты средствами CSS.

Современные браузеры — Flexbox

В современных браузерах (в том числе Internet Explorer 11 и Edge) управлять визуальным порядком элементов можно с помощью CSS-свойства order, являющегося частью механизма Flexbox. Блоки следуют в порядке возрастания значений свойства order. Значением свойства order должно быть целое число, которое может быть как положительным, так и отрицательным. Значение по умолчанию — 0.

HTML:
<div class="example">
    <div class="a">Первый</div>
    <div class="b">Второй</div>
    <div class="c">Третий</div>
</div>
CSS:
.example {
    display: flex;
    flex-direction: column;
}

.example > .a {order: 3; } /* Отобразится третьим */
.example > .b {order: 2; } /* Отобразится вторым  */
.example > .c {order: 1; } /* Отобразится первым  */

Объявление display: flex включает Flexbox для элемента-контейнера. Объявление flex-direction: column задаёт вывод дочерних элементов контейнера друг под другом вместо горизонтального вывода, используемого во Flexbox по умолчанию.

Вертикальное положение переупорядочиваемых является взаимозависимым: увеличение высоты любого из блоков приводит к автоматическому вертикальному сдвигу визуально следующих за ним блоков, в том числе при динамическом изменении высоты блоков, например, вследствие увеличения размера шрифта средствами браузера.

Устаревшие браузеры — display: table

В браузерах, не поддерживающих Flexbox (IE 10 и ниже), вертикальный порядок следования блоков на HTML-странице можно изменить, придав им табличное представление при помощи CSS-свойств семейства display: table. Вне зависимости от порядка расположения блоков в HTML-коде, «шапка» (display: table-header-group) такой таблицы отображается в её верхней части, «подвал» (table-footer-group) — в нижней, а основная часть таблицы (table-row-group) — между ними.

.example {
    display: table;
    width: 100%;
}

.example > .a {display: table-footer-group; } /* Отобразится внизу псевдотаблицы */
.example > .b {display: table-row-group;    } /* Отобразится посередине */
.example > .c {display: table-header-group; } /* Отобразится вверху */

Описанным образом можно изменять порядок до трёх соседних блоков. Дополнительно можно задействовать display: table-caption (отображение блока в роли подписи к таблице) в сочетании с CSS-свойством caption-side со значением top или bottom.

Метод работает в большинстве распространённых браузеров, в том числе в Internet Explorer начиная с версии 9 (IE8 — с оговорками, см. далее).

IE 6, 7 и 8 — DOM

Устаревшие браузеры IE6 и IE7 не поддерживают CSS-свойства семейства display: table*.

Кроме того, в IE8 в некоторых случаях наблюдается динамическая ошибка рендеринга: если перемещаемый блок содержит в себе псевдотабличные элементы (display: table*) (проявление нюанса замечено только в этом случае), возможно спонтанное пропадание некорых ячеек (всегда разных и в разном количестве) псевдотаблицы при первичной отрисовке страницы.

Поэтому для IE8 и ниже можно отменить CSS-правила, придающие блокам табличный вид, и дополнительно переместить блоки в нужные позиции DOM-дерева HTML-документа уже с помощью JavaScript:

/**
 * Перестраивает соседние элементы в DOM-дереве в заданном порядке.
 * @param {Array} elems Соседние элементы в необходимом порядке.
 */
function reorderElements(elems) {
    // http://tanalin.com/articles/css-block-order/
    var count = elems.length;

    if (!count) {
        return;
    }

    var parent = elems[0].parentNode;

    for (var i = count - 1; i >= 0; i--) {
        parent.insertBefore(elems[i], parent.firstChild);
    }
}

Определение возможностей браузера

Использовать разные стили для современных и устаревших браузеров можно путём определения возможностей браузера средствами JavaScript.

Определить, поддерживает ли браузер Flexbox, можно путём проверки существования свойства order объекта, доступного через свойство style корневого элемента документа (<html></html>) — document.documentElement.

Определить версию Internet Explorer можно путём проверки существования нестандартного объекта document.all, доступного только в IE 10 и ниже, в сочетании с существованием или отсутствием одного из стандартных объектов.

if ('order' in document.documentElement.style) {
    // Flexbox-совместимый браузер.
    // Используем свойство `order`.
}
else if (document.all && !document.addEventListener) {
    // IE8 или ниже.
    // Изменяем реальный порядок блоков в DOM-дереве средствами JS.
}
else {
    // Браузер без поддержки Flexbox, в том числе IE 9/10.
    // Используем `display: table`.
}

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

Для изменения вертикального порядка блоков средствами CSS широко применяется абсолютное позиционирование. Блок в этом случае не перемещается, а позиционируется относительно ближайшего родительского элемента, для которого задано CSS-свойство position: absolute или position: relative:

.example {padding: 100px 0 200px; position: relative; }

.example > .a,
.example > .c {position: absolute; left: 0; width: 100%; }

.example > .a {bottom: 0; height: 200px; } /* «Приклеен» к нижней кромке контейнера  */
.example > .c {top:    0; height: 100px; } /* «Приклеен» к верхней кромке контейнера */

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

Способ с применением Flexbox и табличного CSS-представления лишён недостатков абсолютного позиционирования и позволяет получить результат, аналогичный ситуации, когда блоки в HTML-коде располагаются именно в том порядке, в каком отображаются.