Вертикальная пере­становка блоков средствами 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 по умолчанию.

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

Обратный порядок

Если требуется просто вывести элементы в обратном порядке, можно использовать объявление flex-direction: column-reverse для содержащего их контейнера без необходимости явно задавать расположение каждого элемента:

.example {
    display: flex;
    flex-direction: column-reverse;
}

Устаревшие браузеры — 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 — с оговорками, см. далее).

Internet Explorer 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` или `flex-direction: column-reverse`.
}
else if (document.all && !document.addEventListener) {
    // IE8 или ниже.
    // Изменяем реальный порядок блоков в DOM-дереве средствами JS.
}
else {
    // Браузер без поддержки Flexbox, в том числе IE 9/10.
    // Используем `display: table`.
}