Rasmus Fløe

Front-end developer, Copenhagen, Denmark


HTML, CSS, LayoutTweet this

A technique to do advanced flexible layouts beyond standard rows/columns without additional structural markup.

Doing layouts in responsive designs has become synonymous with using a row/column-style grid of sorts. There are any number of frameworks out there providing implementations of said grid-type; it's basically the de facto standard.

But some layouts are impossible to implement without nesting rows and columns - and doing so has its disadvantages:

The misc div

If you are arranging a series of items in a layout and group some of them in one column and the rest in a second - do the columns imply any sort of semantic meaning? No - they are purely there for visual reasons.

Wouldn't it make more sense that the items could be part of a list structure if they were a list of latest news or products in your shop? In those incidents columns do more harm than good.

Mobile F...hird?

It's quite ironic striving for Mobile First while adding structural markup for larger screens. You are bound to make compromises due to having the same row/column markup do meaningful layouts across screen sizes. To get a perfect layout at your largest supported screen size you may be giving up on equally perfect layouts in smaller sizes.

The deteriorating grid

Most grid systems just divide nested rows into 12 new columns. This has the unfortunate effect of dissolving the 12 column grid your designer intended for your page.

Zurb Foundation even acknowledges this somewhat:

You can nest the grids indefinitely, though at a certain point it will get absurd. Advanced | Grid | Foundation Docs

If you divide your layout in a column spanning 7 grid columns and one spanning 5 you are SOL trying to make nested columns inside them align to the page grid (no fraction of 12 matches any fraction of 7 or 5).

Bring Your Own Grid

You're probably already using a floating grid like the ones provided by Foundation and Bootstrap (be sure to check out the live demos further down).

The combine-layout technique will complement your existing grid and fix the problems mentioned above by affording you extra layout flow control - without nesting.

You just use the same measures of dealing with widths the existing grid uses. But the flow of the layout is controlled via selectors rather than structural markup.

Control your flow

This is achieved in the combine-layout technique as a block-level layout in contrast to a row/column one.

Instead of wrapping a number of items in a single column - they are each wrapped in their own column. This means a row and its blocks will essentially have the same relationship that <ol> and <ul> elements have with their <li> child elements.

Blocks will flow side-by-side until they are either forced to wrap onto a new line by the combine-layout or by the naturally occurring right edge of the layout.

This can be done in up to 2 pseudo-columns - each with their own wrapping flow of blocks.

Anatomy of a Combine-layout

The basic technique itself can be implemented with just 3 different roles;

Let's fill the roles with some classnames to make it easier to grasp: combine-layout, combine-break and combine-divide.

The resulting CSS would look like this:

View fullscreenClose fullscreen viewcss.combine-layout {
    font-size: 0; /* make sure whitespace between inline-blocks doesn't ruin the layout */
    text-align: right; /* align inline-blocks right */
.combine-layout > * {
    font-size: 16px; /* reset font-size - alternatively use 1rem */
    text-align: left; /* reset text-align right */
.combine-break + * {
    clear: left; /* force floated blocks down to start new rows */
.combine-divide ~ * {
    float: none; /* reset float */
    display: inline-block; /* switch to inline-block */
    vertical-align: top; /* make sure blocks align at top */

As you can see it's almost embarrassingly simple - but yet very powerful!

A combine-layout will have two different contexts (or pseudo-columns if you will); a floating context and an inline-block context. By default all child elements of the layout will belong to the floating context.

Floating blocks are broken up into rows by using combine-break on the last block in a row. This clears the floating context and forces the next block down to begin a new row.

Using the combine-divide classname will trigger the rest of the elements to belong to the inline-block context. Inline-blocks align flush side-by-side and will automatically be broken into rows by the right-hand edge of the container. No additional layout control needed!

In the following examples - let's assume that we're using a 12 column floating grid system with col-* classnames - and for simplicity we're not concerned with media queries.

The example figures show numbered blocks laid out in source order with a dotted line signifying the divide in layout context.

Example A

A simple layout with each pseudo-column being 6 grid columns wide showing how the combine-divide classname triggers the inline-block context.

The only addition needed is the combine-divide classname on the first block.

The HTML would look something like the following:

View fullscreenClose fullscreen viewhtml<div class="row combine-layout">
    <div class="col-6 combine-divide"><!-- content --></div>
    <div class="col-2"><!-- content --></div>
    <div class="col-2"><!-- content --></div>
    <div class="col-2"><!-- content --></div>
    <div class="col-2"><!-- content --></div>
    <div class="col-2"><!-- content --></div>
    <div class="col-2"><!-- content --></div>

Live demos of the layout using mainstream CSS frameworks with and without combine-layout:



As you can see in the demos using pure floats causes trouble if blocks have different heights; blocks get caught on the corner created by previous blocks. But using floats together with inline-block this is all painless.

The demos also show how the technique can be used in conjunction with media queries. Naming of classnames were changed to better reflect breakpoint names. The examples are slightly different due to the standard breakpoints provided by the libraries being used.

Some different behaviour in the libraries are compensated for; like Foundation floating the last block in rows right and Bootstrap having different font-sizes for root and body.

Example B

This shows a 8-4 pseudo-column combination. Add the combine-break classname on every block adjacent to the dotted line except for the last block to which you add the combine-divide classname. That rounds off the first pseudo-column and starts the next pseudo-column of 4 columns width (inline block context).

This figure also shows how the combine-break and combine-divide classnames are used on blocks aligned to the dotted line.
View fullscreenClose fullscreen viewhtml<ol class="row combine-layout">
    <li class="col-8 combine-break"><!-- content --></li>
    <li class="col-4"><!-- content --></li>
    <li class="col-4 combine-break"><!-- content --></li>
    <li class="col-8 combine-divide"><!-- content --></li>
    <li class="col-4"><!-- content --></li>
    <li class="col-4"><!-- content --></li>

Live demos:





If using a hard reset on font-size causes inheritance issues for you you might want to look at some alternatives:

CSS-Tricks: Fighting the Space Between Inline Block Elements

In closing

As you may be able to tell combine-layout offers quite a bit of extra leeway without having to resort to wrapping everything up in nested rows and columns.

But what about flexbox and CSS Grid? If all you need to support is IE10 and better and you don't need the advanced layout features combine-layout affords you - you might as well go with it. Be sure to work around the missing column-wrap in FireFox though (fixed in Firefox 28, released on March 18 2014).

CSS Grid is coming - but is more designed as a solution to page layout than content flow. As such it's like comparing apples to oranges that haven't even been picked yet ;)

Combine-layout can be used now - with whatever floating grid system you're using already. It will let you keep semantic structure and flexibility across screen sizes and is supported in browsers starting from IE8 and up.

What more reasons do you need to try it out?