Skip to content ↓


Vertical reordering of blocks with CSS

Summary
Cross-browser method for full-fledged vertical reordering of blocks of arbitrary height with CSS.

Modern browsers — Flexbox

In modern browsers (including Internet Explorer 11 and Edge), visual order of elements can be controlled using the order CSS-property that is a part of the Flexbox layout mechanism. Blocks follow according to the order-property values in increasing order. Value of the order property must be an integer number (both positive and negative values are allowed). Default value is 0.

HTML:
<div class="example">
    <div class="a">First</div>
    <div class="b">Second</div>
    <div class="c">Third</div>
</div>
CSS:
.example {
    display: flex;
    flex-direction: column;
}

.example > .a {order: 3; } /* Will be displayed third  */
.example > .b {order: 2; } /* Will be displayed second */
.example > .c {order: 1; } /* Will be displayed first  */

The display: flex declaration enables Flexbox for the container element. The flex-direction: column declaration makes child elements to be under each other instead of horizontal output used in Flexbox by default.

Vertical positions of the reordered blocks are interdependent: vertical enlargement of any block results in that visually next blocks are automatically shifted vertically, including cases when a block’s height is changed dynamically, for example, as a result of increasing font size via browser settings.

Old browsers — display: table

In browsers that do not support Flexbox (IE 10 and older), it is possible to change vertical order of blocks on an HTML page using CSS table presentation via properties of display: table family. Regardless of block order in HTML code, header (display: table-header-group) of such table is displayed at the top of it, footer (table-footer-group) — at the bottom, and table body (table-row-group) — between the header and the footer.

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

.example > .a {display: table-footer-group; } /* Will be displayed at the bottom of the pseudo-table */
.example > .b {display: table-row-group;    } /* Will be displayed in the middle */
.example > .c {display: table-header-group; } /* Will be displayed at the top */

With this technique, it is possible to change order of up to three sibling blocks. Additionally, it’s also possible to utilize display: table-caption (displaying a block as table caption) in conjunction with caption-side CSS-property with the value of top or bottom.

The technique works in most of popular browsers, including Internet Explorer 9+ (using the technique in IE8 is limited, see below).

IE 6, 7, and 8 — DOM

Old browsers IE6 and IE7 do not support CSS properties of display: table family.

Also, IE8 has a dynamic rendering bug that appears in some cases: if a block to move contains preudo-table elements (display: table*) (this is the only buggy case noticed currently), some pseudo-table cells (such cells as well as cells count are different each time the page is reloaded) may disappear randomly when the page is initially rendered.

So, for IE8 and lower, we can override CSS rules that make blocks tably, and additionally move blocks to required positions in DOM tree of HTML document with JavaScript instead of CSS:

/**
 * Reorders sibling elements in DOM tree according to specified order.
 * @param {Array} elems Sibling elements in desired block order.
 */
function reorderElements(elems) {
    // http://tanalin.com/en/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);
    }
}

Detection of browser features

To use different styles for modern and old browsers, JavaScript-based feature detection can be used.

To detect whether a browser supports Flexbox, test whether the order property of the object available via the style property of the root element of the document (<html></html>) — document.documentElement — is available.

Internet Explorer version can be detected by checking existence of the nonstandard document.all object available in IE 10 and older, in conjunction with existence or absence of one of standard objects.

if ('order' in document.documentElement.style) {
    // Flexbox-compatible browser.
    // Using the `order` property.
}
else if (document.all && !document.addEventListener) {
    // IE8 or older.
    // Changing the real order of blocks in the DOM tree via JS.
}
else {
    // Browser with no Flexbox support, including IE 9/10.
    // Using `display: table`.
}

Absolute positioning

To change visual vertical order of blocks with CSS, absolute positioning is widely used. In this case, block is not actually moved, but positioned relatively to nearest parent element that have position: absolute or position: relative CSS-property:

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

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

.example > .a {bottom: 0; height: 200px; } /* Positioned to the bottom of the container */
.example > .c {top:    0; height: 100px; } /* Positioned to the top of the container    */

A big shortcoming of absolute positioning is that positioned block is removed from normal element rendering flow and does not affect positions of next sibling elements anymore. So, absolute positioning is applicable to reorder blocks only in cases when height of positioned block is known in advance and does not depend (or depends a little) on font-size settings of browser or operating system.

Using Flexbox and CSS table presentation is free from shortcomings of absolute positioning and allows to achieve a result similar to when block order in HTML code is exactly the same as its visual order on rendered page.