Grow your CSS skills. Land your dream job.

Content Folding

Published by Chris Coyier

Less than a year ago, Trent Walton published Content Choreography in which he lamented at some of the difficulties and limitations of responsive layouts.

At times, it seems as though all of the site architecture & planning goes out the window as content reflows.

You have to admit, an awful lot of responsive designs end up being:

  1. Squeeze everything into one column
  2. Push the sidebar(s) to the bottom

*cough* this site does that *cough*

Trent mentioned it may be a more appropriate approach to "interdigitate" content.

Interdigitate

That is, to fold bits of content together into that single column in a more thoughtful or useful manner.

A Practical Example: Ad Folding

Consider a layout at a large browser window size. Two columns. Articles in a wide column on the left, advertisements in a narrow column on the right.

At narrower browser window sizes we've decided to drop down to a single column. This layout is probably done with floats, the most common layout method still today. Unfortunately that probably means setting both columns to 100% wide and letting their source-order determine which is on top. Meaning: push all the ads to the bottom. Probably not ideal. It likely would be nicer to fold the ads into the content.

But how?

There's probably a number of ways to do this. With JavaScript, you could measure the window width and shuffle things around in the DOM. That seems heavy to me, but the browser support would be good. I'd rather lean on CSS for this kind of thing. That's what CSS is (supposed to be) for. The grid layout may hold some possibilities for us, but for this tutorial, let's use the hot-off-the-presses CSS Regions, a contribution by Adobe.

Fair warning: This stuff is super new and subject to change. When I wrote this in March 2012, this demo worked in Chrome. Now in January 2013, it doesn't anymore. Chrome 15-18 had partial support and then it was pulled in 19, although Chrome still reports support of the property.

HTML

<section class="main-content">

  <article> ... </article>

  <div class="ad-region-1">
    <!-- empty, ads flow into here as needed -->
  </div>

  <article> ... </article>

  <div class="ad-region-2">
    <!-- empty, ads flow into here as needed -->
  </div>

  <article> ... </article>

  <div class="ad-region-3">
    <!-- empty, ads flow into here as needed -->
  </div>

</section>

<aside>
   <!-- Fallback content in this flow region, probably clone #ad-source -->
</aside>

<!-- Source of flowing content, essentially hidden as an element -->
<div id="ad-source">
  <a href="#"><img src="ads/1.jpg"></a>
  <a href="#"><img src="ads/2.jpg"></a>
  <a href="#"><img src="ads/3.jpg"></a>
  <a href="#"><img src="ads/4.png"></a>
</div>

Notice the "content" (our ads) are tucked into a <div> at the bottom of the page. Once we set up the CSS regions, the element will essentially be hidden and the content inside it will flow into the regions we tell it to.

CSS

We kick it off by telling our content-holding div#ad-source to flow it's content into a "named flow":

#ad-source {
  -webkit-flow-into: ads;
  -ms-flow-into: ads;
}

I'm only using two vendor prefixes here because that's the only support for now. I'd recommend not using the unprefixed version as this stuff could change in final implementation.

'ads' is an arbitrary name that we just made up. It could be anything, like naming a CSS animation.

Now we set up regions in which for that content to flow. First, into the aside, then into the interdigitated divs between the articles.

aside, [class^='ad-region'] {
  -webkit-flow-from: ads;
  -ms-flow-from: ads;
}

In our case, at wide browser window widths, the aside is large enough to hold them all. At narrower widths, through media queries, we hide the aside, forcing the content to flow into the divs.

[class^='ad-region'] {
  display: none;
  height: 155px;
  width: 100%; /* Weird that this is required */
}

@media (max-width: 800px) {
  [class^='ad-region'] {
    display: block;
  }
  [class^='ad-region']:last-child {
    height: 300px; /* I wish height auto worked */
  }
  aside {
    display: none;
  }
}

Semantics

Soooo yeah, we have some empty elements we're tossing around here. Not super semantic. I'm not sure what this does for accessibility either. I do know that the DOM doesn't change around. All the content, despite where it "flows", is still within the "source" (the element with the flow-into property).

Here's the thing though: regions are layout style agnostic. We're still using floats for layout in this example, but the layout style you use doen't really matter. Regions paired up with the CSS Grids might be much more powerful and more semantic (I just don't know).

Browser Support

CSS Regions is shipping in Chrome 16 through 20, then put under the flag "Enable CSS Regions" in 21-22, and now under the flag "Enable experimental WebKit features" in Chrome 23+. It works in Safari 5.2 (available as dev, or WebKit Nightly). Supposedly it works in IE 10, but I couldn't get it to.

Demo & Download

For your enjoyment:

View Demo   Download Files

Please note the browser support above, it's very limited.

Also note that at some fairly wide browser window widths, the ads in the aside get cut off. I'm leaving it that way to illustrate how regions don't expand in height naturally, you need to account for that yourself.

Update: This demo worked, then was broken, and now works again. I made it work through Adobe's CSS Regions Polyfill. This will need to be revisited again when the spec and browser support settles down.

Browser Detection

This HTML and CSS as is would be pretty sucky in a browser that didn't support CSS regions. There would be this chunk of ads at the bottom of the page randomly. Instead I chucked in a bit of JavaScript (based on this) to test for it and apply classes to the html element reflecting support.

// Generic Testing Function
var supports = (function() {  
   var div     = document.createElement('div'),  
       vendors = 'Khtml Ms O Moz Webkit'.split(' '),  
       len     = vendors.length;  
  
   return function(prop) {  
      if (prop in div.style) return true;  
  
      prop = prop.replace(/^[a-z]/, function(val) {  
         return val.toUpperCase();  
      });  
  
      while (len--) {  
         if (vendors[len] + prop in div.style) {   
            return true;  
         }  
      }  
      return false;  
   };  
})();  
  
// Test
if ( supports('flowInto') ) { 
   $("html").addClass('cssregions');  
} else {
   $("html").addClass('no-cssregions'); 
}

That was we can do stuff like this to make sure the fallback is OK:

#ad-source {
  display: none;
}
.cssregions #ad-source {
  display: block;
  -webkit-flow-into: ads;
  -ms-flow-into: ads;
}

And also, copy the contents of the div#ad-source into the aside, so at least the ads appear there at the widest browser window widths.

This should work, but it is reporting false positives in Chrome since Chrome removed support for it in Chrome 23. You can turn on support though...
  1. Using the browser bar navigate to chrome://flags
  2. If you're running Chrome 21 or Chrome 22, find the "Enable CSS Regions" flag and enable it
  3. If you're running Chrome 23 or newer, find the "Enable experimental WebKit features" flag and enable it.
  4. Restart your browser by clicking the "Relaunch Now" button on the lower left corner.

If you wanted to add this test to Modernizr you'd do:

Modernizr.addTest('regions', Modernizr.testAllProps('flow-into'));

Hopefully they'll add that as an option in future versions.

Things I Wish Were Better

  • I wish you could style content based on what container element it happens to flow into. That might be problematic as a different style in a different container might cause a reflow which pushes it back out of that container causing infinite looping sadness, but maybe there is some kind of solution for that.
  • I wish block level elements would remain block level even with the flow-from property. It's weird you have to set them to width: 100%;
  • I wish height: auto; worked on the region with the last bit of flowed content. I understand most flow regions can't do that because then they would just expand to fit all the content and not continue the flow, but the final region should be able to know what it has left and expand naturally.
  • I wish you could flow-from and flow-into the same element. That way one semantic element could be the source and only if it shrinks or goes away do the other regions get filled.

Comments

  1. Jill
    Permalink to comment#

    I definitely dislike websites which shove everything into one column.

    With desktop layout (on mobile) I can simply scroll sideways to get to page navigation.

    With “responsive” zoom is broken and navigation is far far away with only 100%-sized scrolling available.

    Please just do nothing for mobile! I like zoom!

    • Permalink to comment#

      I don’t really agree with you there. If zoom is disabled on mobile layouts it means that the designer has fixed the maximum-scale to 1.0 which is naughty for a number of reasons not least accessibility. The only thing it apparently cures is device rotation.

      However, my site for example is fully responsive but text and everything else can still be zoomed because I think it’s more important to be accessible than to suit a user rotating their ipad. After all they can quickly zoom-out and it fixes.

      I do agree with your point about Navigation however, perhaps a fixed nav bar or anchor link that takes you back to the top might be something to look at. I’m aware that iOS devices do this for you though if you tap the title bar area up top.

  2. Permalink to comment#

    This is very timely for me as I’ve been contemplating how I’ll merge two content list columns for an upcoming project.

    As you point out, browser support is currently lacking for this method but it’s one to keep an eye on.

    The only alternative I can think of currently is altering HTML on the fly with jQuery at different device widths. Specifically, moving the items in two columns into one, and then ordering chronologically. A pure CSS way would be preferable.

    Good post!

  3. Hi Chris, like the article. As for screen readers – as the DOM is not being re ordered this is probably a good thing the Ads are at the base?

  4. Angelo
    Permalink to comment#

    another solution could be to put the ads in both places (sidebar AND between articles) and show or hide them depending on the window’s width!

    • That is a rather ingenious workaround.

    • Ben Colegate
      Permalink to comment#

      I agree! Clever idea, but it could be a problem in Googles eyes as it might see your content is covered with ads!

      I could be wrong about this, but thats just my feeling.

    • For google ads, I’m fairly sure you aren’t allowed to “hide” the ads. In the terms and conditions I believe.

    • Shawn McCarthy
      Permalink to comment#

      I like this solution better, actually. And I wouldn’t worry about Google “seeing a bunch of ads” because the entire containing div doesn’t even show up in the resulting html (I believe). Thus, Google will only see one set of ads.

    • The biggest problem with ad serving and show/hiding them is the analytics. If tools like Omniture and Analytics are used to track ads, then a hidden ad on a page is a very bad thing. Most tracking software will denote that ad as underperforming, and they are not yet smart enough to differentiate from the hidden ads and the ads that are in view.

  5. Great post Chris! I for one am really excited about the future – wider implementation of this, as pure CSS, would make it a great addition to sites with the two column setup.

  6. great site – it´s cool to check this out. but the content folding not working 100% on my browser, because the images are hidden when page-width is smaller than (maybe) 800px. best regards from germany

  7. Joe Banks
    Permalink to comment#

    I’ve tried addressing this issue earlier and I ended up settling with a combination of float: left and float: right declarations.:

    http://jsfiddle.net/GL9sM/3/embedded/result/

    The drawback to this method is that a container can only go as far up the page as the top of its preceding sibling.

  8. I like the future possibilities of regions.. but the support just isn’t there. Doesn’t seem like the kind of thing that should be polyfilled as a fallback. Just do it in Javascript in the first place.
    For WordPress… I like the idea of adding an ad to the loop.php(or content.php or whatever) and output and article and an ad paired. Then let things float to single column when the width gets to narrow. It’s the “ad on the bottom” solution, but per article. And we can do it now. The two per article could work as well. I think I’m going to try it this weekend with a clients’ theme.. see if he likes it. It’s not ads, but testimonials. I think it could work out nice!

    btw.. “interdigitate” is 15 points in Scrabble.

  9. When I shrink my screen, the ads simply disappear. That’s AWESOME!!!!

    I wish it was that easy to get rid of ads on tv : )

  10. Phil
    Permalink to comment#

    Awesome as usual

  11. WTF?! oO

    Chris Coyier, the hero of CSS!

  12. Jimmy McElhorne
    Permalink to comment#

    Your Comment Preview is a perfect example of focusing attention on sh*t that doesn’t matter. Sure it’s a neat little trick, but it slows the user’s typing down to a snail’s pace.

    In regards to the article…

    1.) Most of your viewers are nerds whose screen resolution is large enough to accommodate two columns
    2.) Most of your viewers are nerds who have ad block plus running
    3.) Most people do not sit there resizing the browser window to see what happens.

    • Am I missing something here? All three of your points are invalid. The main purpose of this article (as well as almost all of the articles on this site) is to share techniques with other developers to use on their own projects; it’s not tailored specifically for css-tricks.com.

  13. Dear Jimmy, in regards to this article, it’s not for the nerds browsers. :) It’s for we who build for clients who have a variety of screen sizes (not because they resize). We who have clients who don’t block ads…

    It’s an experiment at a creative solution for adapting to screen resolutions… along with playing with source order, etc. It’s not a perfect solution (there isn’t one yet) but I for one welcome the experimentation and sharing. Thanks Chris!

    (Not sure what happens with your browser with comment preview, but I’m not slowed at all in Chrome.)

    Have a nice weekend! :)

  14. Thanks,
    I didn’t know about the “flow-into” a div

  15. Barney
    Permalink to comment#

    I don’t understand the upper carat and brackets in “[class^='ad-region']“. Can someone explain the notation and how it’s being used?

    • Select all elements that have a class attribute with ad-region as the starting value. That mean: ad-region-1. ad-region-2, ad-region-3, ad-region-wow.

  16. Barney
    Permalink to comment#

    Thank you. Makes sense now; for some reason it just wasn’t sinking in before.

  17. CSS Regions seem the perfect way to break semantics in my eyes.

    For this specific example i.e. ads (as they are generally a fixed height), I would suggest interleaving the them in the markup and then using absolute positioning to shift them to the side column when on wider devices.

    • Clint
      Permalink to comment#

      This is basically the solution I arrived at for a recent project – it worked ok, but can be a bit problematic for sites with numerous/complex templates.

      Good article though, love seeing any new ideas on how to tackle this issue.

  18. Speaking from a commercial point of view:

    You will find it difficult to justify re-sizing ad’s like that to a client. If you sell a client a 300×250 adblock, it’s got to remain 300 x 250 across all responsive folds/layouts. So trying to sell this zoom option to a business investor is going to require some serious sales skills.

    I think leader boards would be the biggest problem. The only solution I see is to swap the entire ad out with a different dimension version at lower resolutions.

    _jin

  19. thanks for tutorial :)

  20. Really nice work around.

    Peter Avey

  21. I don’t have a huge issue with the placeholder divs with respect to screen readers. You can, of course, inject them with JavaScript, but the W3C states (HTML4 spec; couldn’t find anything in the HTML5 spec):

    “We discourage authors from using empty P elements. User agents should ignore empty P elements”

    Tags are meant to give context to content. By that logic, I like to think that an empty tag is like a sentence without any words.

  22. I agree with Matthew Balaam.
    Anyway, Thanks for this tutorial!!

  23. This is good stuff. And the example works for calls-to-action just as well as for ads.

  24. pixelutely
    Permalink to comment#

    Ooh, me likey! Works well in Chrome 17.

    The ads don’t appear for IE8 and Firefox at all tho.

  25. Very cool! Thanks for those CSS3 Tricks.

  26. maxw3st
    Permalink to comment#

    I’ll try this out in an upcoming WebDev class. Looks like a great solution.

  27. I wasn’t sure if there could be a legitimate use of CSS regions – all those demos of absolutely positioned containers on images – but this is pretty cool. There’s a good level of abstraction between content and presentation but the empty DOM nodes will make lots of purists shiver – has anyone tested if reflow will work with pseudo-elements?

    • Yes, yes they can…

      While the example uses elements as regions (since [CSS3-GRID-LAYOUT] requires elements to create grid items) it is important to note that this is not required for regions. Regions can be pseudo-elements, such as ‘::before’ and ‘::after’. The only requirement for an element or pseudo-element to become a region is that it needs to be subject to CSS styling to receive the ‘flow-from’ property.

      http://dev.w3.org/csswg/css3-regions/#named-flows-and-regions

  28. condimen
    Permalink to comment#

    Thank you, as always

  29. I just agree with Matthew Balaam. Anyway, Thanks for this tutorial!!

  30. Such a good point. I also imagine that those that have ads on our sites aren’t thrilled about them always getting pushed down to the bottom from their premium top-of-the-sidebar spot as soon as things get narrow, so this is pretty sweet.

  31. Very clever and perfect solution for responsive design. I love CSS Region. Now waiting for the browser support ;D

  32. Josh
    Permalink to comment#

    sorry, but I have a question about implementing both. Say you have a site with a column of news feeds on the right but the news feeds are more than what is in the center page. Well, is there a way to automatically move some of the news feeds under the center page until you keep adding more text to the center page, then it would revert the news feeds back over to the right column? css of course.

Leave a Comment

Current day month ye@r *

*May or may not contain any actual "CSS" or "Tricks".