Any Order Columns
A method for keeping columns (or more precisely, blocks of elements [note]) logically ordered in the source while still providing the designer the ability to display them in any order whatsoever without the need for any additional non-semantic markup.
It's good for the users
Browsers that do not make use of the CSS positioning information will present the content in the order that it is marked up. Consequently the ordering of content in the source code is important as far as accessibilty [note] and assistive technologies are concerned. [note]
It's good for you
The overriding rationale behind CSS is the separation of content and style - the removal of non-semantic cruft and complete ordering flexibility theoretically allows for repurposing of content without the need for tweaking html.
Although this might be less useful for an individual's site where markup can be altered to accomodate design changes, this is a huge win for systems based on templates where changing the html is either impossible or undesirable.
Furthermore it promises even greater customisability of a site for individual users. For instance, side columns could be swapped over or even placed on the same side (though whether this would be a good idea or not is debatable).
It's good for you and the users
Search engine spiders/robots read web pages like this - they start at the top left, read across, and then move down. Consequently the ordering of content on a page is important as far as search engine algorithms are concerned. [note]
Through the magic of floats and (when necessary) negative margins. Each block is floated in the following way:
- Work out the desired leftmost point of the current block - Current Left
- Work out the rightmost point of any of the floated blocks that precede the current block in the source - Preceding Right
- Subtract Preceding Right from Current Left to give the current block's
margin-left- Current Margin
If we want the column blocks of our layout to be the same width and ordered 2-1-3, the maths work out like this:
|Current Left||Preceding Right||Current Margin|
|Block 1||33%||N/A||33 - 0 = 33%|
|Block 2||0%||67% (Block 1)||0 - 67 = -67%|
|Block 3||67%||67% (Block 1)||67 - 67 = 0%|
So given this HTML markup...
... we apply the following CSS:
Is it really that simple?
Of course not. It never is, is it? This method runs head first into a peculiarity in the layout engine of IE Win (5 and 6) - if block 1 is not the first column, it requires its margin-left to be divided by 2.
Investigating further, we find that the bug is triggered for any block n (where n is the position of the block within the source code) if:
- column positions 1 to n-1 are occupied by blocks 1 to n-1 (in any order)
- block n occupies column position 2n or greater
Under such circumstances element n will require its margin-left to be reduced - the overall number of columns appears to be irrelevant.
Keen readers will have noticed and been chomping at the bit to point out that this is the dreaded IE Doubled Float-Margin Bug. Well spotted. The good news is that the usual fix works just fine.
All that is required is
display: inline targeted at IE for the element in question. It's only the first such block in the source ordering that needs this "hand holding" and once the fix is in, it magically sorts out any following elements which would otherwise need the fix.
So in the code example, block 1 is to appear as column 2 and triggers the bug, since its column position is equal to 2 times its source position [note]. Consequently we need to add the following CSS:
So it's very nearly that simple. Or rather it is that simple. It's actually possible to simply set all the column elements to
display: inline (as far as IE is concerned) without any unfortunate side effects and without any need to work out whether any of the column blocks need the hand-holding or not. [note]
Wrapping things up
As things stand in the example, there's no wrapper/container element holding the columns together. More often than not, you're going to want or probably even need one. Most likely, if you want to apply a faux-columns style background to the columns (or utilise the techniques developed later in this article), there's the not-so trivial matter of making sure that the container expands to fully contain the columns. And so the simple method sketched out so far becomes a little messier again.
Over the years, several non-cruft-introducing methods have been invented to deal with this. Unfortunately though, the
overflow: hidden method causes everything to just blow up. And a bug in Firefox/Mozilla means that you can't use the simple floated container method, if, but only if, the longest column has actually been negatively shifted. That's a pretty big if, though. Using
display:table works fine for a pure any order solution, but I've not used it here because it runs into trouble later on.
Fortunately, the original (and still the best ;) EasyClearingTM works just fine, if somewhat more verbosely than the alternatives.
The method even holds up if you want to use
direction: rtl. In that case you just switch right for left in the column float and margin declarations.
Danger, er, Alex Robinson!
This method is, being a float-based method, prone to the usual float method problems. Because IE (both Win and Mac) violates the specs and expands elements to be at least the width of the largest nested element, things can get funky. This means that unexpectedly wide images or long unbroken strings of text will cause havoc with the layout.
NB. these problems are intrinsic to any float techniques in IE, and are not caused by the use of negativity itself, but because elements are being negatively shifted, an unexpected float wrap could cause some of those elements to be placed beyond the left edge of the viewport. Consequently, particular care should be taken with the following issues:
- the expanding box problem
- rounding errors when using ems or percentages
- quirky percentages in IE6's visual formatting mode
Other likely IE problems can be found at Position Is Everything's Explorer exposed! and Windows Explorer vs. the Standards. See also On having layout, the extremely thorough dissection of IE's layout engine quirks.
Works fully in
IE Win 7 beta 2, IE Win 6, IE Win 5.5, IE Win 5.01, IE Mac 5, Operas 7, 8 and 9, Firefox 1.5 [note] and 1.0, Netscape 8, Safari 1.03 (and up), OmniWeb 5
Doesn't work fully in
Netscapes 6 and 7
If the longest block has been negatively shifted under any circumstances (either directly or indirectly, so that it displays before any block that precedes it in the source order), its height is ignored. Instead Netscape treats as longest the longest block that has not been negatively shifted. This can cause any following elements to not be cleared correctly. Apart from that massive stumbling block, it works just great.
This technique does not work in Opera 6 or Netscape 4. As is. That's right, it's possible to even make it work in those browsers if you really want to. That's so insane though, that I'm putting the details of how in this appendix.
Opera 5 is another matter - the blocks never become columns, stretching to fill the width of the container and stacking up on top of each other just as if they were regular unfloated blocks. Except that the column background colours don't show up. Well, if you must support Opera 5...
IE 4? I've got no idea. I can't get it to run on any of the Windows machines I've got access to. I don't imagine that it will behave very well though. Or in IEs 2 or 3. Or Netscape 2 or 3.
The method is both robust and generic. It allows for proper logical source ordering with the flexibility to layout in pretty much any manner. [note]
However, it is certainly true that the columns can shift a pixel or two when percentages are used. If you can guarantee the longest column, the Ordered Absolute method gives more precision for percent-specified layouts.
Tom Wright's CSS Negative Margins Algebra is another CSS-plus-negatively- margined-float approach that's more than worth a look. While perhaps not being as generic as this method, it does allow you to completely remove any interdependence between the positional CSS and the underlying semantics.
The original Source Ordered Columns [note] goes a long way towards satisfying the same issues that the Any Order technique does, but it requires a semantically unnecessary inner wrapping tag to group some of the columns together. This reliance on an inner wrapping tag also limits the number of possible column orderings. Removing the need for the inner wrapper allows all possible orderings to be achieved (though the inner wrapper can serve other purposes. See Appendix H for the theory of possible orderings.
It would be criminal not to mention Ryan Brill's Creating Liquid Layouts with Negative Margins, Thierry Koblentz's neat riff on Ryan's original 3 columns fluid layout, Doug Livingstone's CSS Columns and Position is Everything's Piefecta
All these methods provide a way for mixing pixel widths in liquid layouts. A variation on the basic Any Order technique which can achieve the same results can be found here.
Because the web never sleeps...
Eric Meyer had a brainwave in the middle of a workshop and came up with Multi-Unit Any-Order Columns which does exactly what it says on the tin.
Matthew Levine went questing for a better way to mix pixel widths into liquid layouts in In Search of the Holy Grail.
Now that we have the freedom to put our columns in any old order, let's move on to that perennial CSS favourite, how to make them the same height.
- Tragically, the parlous state of web design and screen readers may already have hardcoded users' expectations. See Source Order, Skip links and Structural labels for details.
- What do I mean by an element? Or by a tag? See Roger Johansson for enlightenment
- In my opinion, a CSS-based layout that orders its content just to achieve a particular design is no better than an old skool table-based one. In fact a table-based design might (under some circumstances) be more accessible since current browsers can use well-established rules to intelligently change the display order, eg. Opera's Small-Screen Rendering for mobiles and PDAs.
- Though obviously this is no magic bullet substitute for actually having relevant content in the first place. For a more thorough explanation, read the section entitled "Position Your Keywords" in this Search Engine Watch article. Some go so far as to claim that high quality markup will help boost your rankings.
- If you need to mix units, head on over to the reimagining of the Holy Grail for a solution after yet more browser pantsdom.
- The same principle can be worked from right to left, using
float: rightinstead (simply switch right and left in the previous instructions). Moreover, left and right floats could be combined. This would have the advantage of ensuring that the left and rightmost floated elements line up with the edge of the wrapper div and also potentially reduce the number of elements requiring negative margins (depending, of course, on just how many columns are required and how they need to be ordered).
- Ultra keen readers will be wondering what happened to
column positions 1 to n-1 are occupied by blocks 1 to n-1 (in any order). The answer is that actually the "real" formula is
column positions 0 to n-1 are occupied by blocks 0 to n-1 (in any order)where ghost block 0 always fills ghost column slot 0. But that's a little confusing, isn't it?
- Andrey Petrov wrote in to point out that this was bust in IE6 - the cause? Because it's in standards mode, IE6 works out the percentages based on the entire body width, rather than the available space within in it. The cure for this, which after all is just a demo, is to zap the body's margin and padding. And to set
#footerto prevent wayward painting of its background colour.
- Not that things are that complex in any case. In three column layouts only the first block will ever need adjusting, and only if it's not to be the first column. The same holds true for four column layouts with the single exception that the second block would need adjusting instead of the first block if the first block was the first column and the second block was the fourth, ie. last column. However, as mentioned above, there's no harm in just applying
display: inlineto all the blocks and not having to bother thinking about any of this.
- Except for the betas and release candidate 1 of Firefox 1.5. See here for details. The same problem affects Camino 1.0a1.
- Blocks don't just have to be displayed as columns - they can be stacked on each other or removed from the flow entirely. I ruminate more about this in the appendix on theory. And there's no need for headers not to follow the main content either if they're not the actual content - Any Vertical Order.
- For examples of the original source-ordered technique, see Five Easy Companion Pieces, several layouts that were published simultaneously with Big John's essay. Sharp eyes will notice faux columns (and liquid ones at that) lurking amongst them.