Vertical reordering of blocks with CSS
- Marat Tanalin
- Published:
- Updated:
- Summary
- Cross-browser method for full-fledged vertical reordering of blocks of arbitrary height with CSS.
Modern browsers — Flexbox
Arbitrary order
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.
Reverse order
If all you need is just to show elements in reverse order, you can use the flex-direction: column-reverse
declaration for the container that contains them, with no need to specify order for each of elements explicitly:
.example {
display: flex;
flex-direction: column-reverse;
}
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 the 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).
Internet Explorer 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 cell 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 `order` or `flex-direction: column-reverse`.
}
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`.
}