Skip to content ↓

Vertical reordering of blocks with CSS

A technique for full-fledged cross-browser vertical reordering of blocks of arbitrary height with CSS.

It is possible to change vertical order of blocks on an HTML page using CSS table presentation via properties of display: table family. Regardles of block order in HTML code, header (table-header-group) of such table is displayed at the top of it, footer (display: table-footer-group) — at the bottom, and table body (table-row-group) — between the header and the footer.

<div id="example">
    <div id="block-1">First</div>
    <div id="block-2">Second</div>
    <div id="block-3">Third</div>
#example {display: table; width: 100%; }

#block-1 {display: table-footer-group; } /* Will be displayed at the bottom of the pseudo-table */
#block-2 {display: table-row-group;    } /* Will be displayed in the middle */
#block-3 {display: table-header-group; } /* Will be displayed at the top */



Unlike absolute positioning where block height should be known in advance, blocks may have any height here. Vertical positions of the blocks will be interdependent: vertical enlarging of a block will result visually next block to shift down correspondingly (including cases when height is changing dynamically, for example, as a result of increasing font size in browser settings).

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: top/bottom CSS-property. But take into account that, in Opera 11 browser, links inside of such preudo-caption element was unclickable or did not respond to mouse hovering, ignoring CSS properties for :hover preudo-classes (the bug id in Opera’s bug tracker is DSK-338752). Starting from at least Opera 12, the issue seems to be fixed.

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

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) {
    var count = elems.length;

    if (!count) {

    var parent = elems[0].parentNode;

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

// If IE8 or lower (
if (document.all && !document.addEventListener) {
    var blocks = [


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; }

#block-3 {position: absolute; left: 0; width: 100%; }

#block-1 {bottom: 0; height: 200px; } /* Positioned to the bottom of the container */
#block-3 {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 CSS table presentation is free from shortcomings of absolute positioning and allows to get a result similar to when block order in HTML code is exactly the same as its visual order on rendered page.