Tuesday, 27 August 2013

The CSS Regions Module — Control Where Content Flows - Vanseo Design

The CSS Regions Module — Control Where Content Flows - Vanseo Design


The CSS Regions Module — Control Where Content Flows

Posted: 26 Aug 2013 05:30 AM PDT

Would you like more control of your content and how it flows through your layout? Would you like an easy way to create more complex layouts? How about an easy way to independently style sections of a document, without complicated css rules that overwrite each other? If you answered yes to any of these questions, then css regions might be what you’re looking for.

The last couple weeks I’ve been exploring css that’s on its way, but not quite here. So far I’ve looked at the css exclusions module, including css shapes. Today css regions are on the menu and while we can’t use them in production just yet, we can start experimenting and learning how they work.

Browser support has a long way to go. Regions are supported in IE10+ (in limited form), Safari 7.0+, and iOS Safari 7.0+ Safari is currently in version 6, but that will change in the fall or you can grab a copy of Webkit Nightly. Chrome Canary also offers support if you enable the experimental Web Platform features flag. You can grab copies and get instructions here.

regions empty and filled
Diagram showing regions (left) and how they might be filled with content (right)

What are CSS Regions?

CSS Regions provide a more advanced mechanism for how content can flow through a document and allow us to create more complex and dynamic layouts than we can right now. A region is a block container that creates a new stacking context and a new block formatting context.

They allow content to flow across multiple areas that don’t need to be contiguous. Region 1 could be in the middle of the page, region 2 and the bottom, and region 3 at the very top. Each region and the elements inside of them can then be styled independent of the others.

To create regions in your layout you define containers in your html and give them ids like region1, region2, and so on. You write css to locate these containers or regions the same as you would any other element. You can float them or position them or whatever you want.

In another part of your html you have content perhaps inside an article tag. By connecting the article with the regions through a named flow you tell the article to flow through the different regions. Here’s how the css might look.

1  2  3  4  5  6  7  
article {    flow-into: article-flow;  }    #region1, #region2, #region3, #region4 {    flow-from: article-flow;  }

In the code above the regions are region1, region2, etc. The order they appear in the html source is the region chain. The way they’re listed in the css doesn’t make a difference. The named flow connecting everything here is “article-flow”

Working with CSS Regions

CSS regions require two properties. The first, “flow-into,” places an element or the contents of an elements into a named flow and specifies if everything inside or just the content of an element should be placed into that flow.

1  
flow-into: none | <ident> [element|content]

For example the css below

1  
article {flow-into: article-flow}

creates the named flow called article-flow. By default (or by using the element keyword) the element itself is placed in the named flow. If you specify content as the value, then only the element’s content will be placed in the named flow.

The second property, “flow-from,” turns block containers into regions and associates them with a named flow.

1  
flow-from: <ident> | none | inherit</li>

You can use the property on each individual container

1  2  
#region1, #region2, #region3, #region4 {  flow-from: article-flow; }

or on a shared class

1  
.region { flow-from: article-flow: }

or anything else that targets the specific containers you want to target.

Content will flow through the regions based on the source order of the regions in the html, but you can use css to locate each region wherever you want.

For example in the html below content will flow through region1, region3, region2, and region4 in that order. However, using floats, positioning, flexbox, or whatever you want to layout the page you could display region4 in the top left and region1 in the middle right.

1  2  3  4  
<div id="region1"></div>  <div id="region3"></div>  <div id="region2"></div>  <div id="region4"></div>

region flow break properties

You can set rules for how content breaks between regions. If you’re familiar with css multi-column, these properties and how they work should be familiar to you.

  • break-before
  • break-after
  • break-inside

Two new values are added to each of the above.

  • region — Always force a region break before (after) the generated box.
  • avoid-region — Avoid a region break before (after, inside) the generated box.

I’ll refer you to my post about multi-column css for more details, but the gist is the above properties and their values tell your content when to break and where they should appear next.

For example if you set break-after: region on a heading, the heading will appear in one region and whatever comes after is forced into the next region.

While the spec simply lists these properties as above, I had to use -webkit-region-break-before, etc. in order to get them to work in Chrome Canary.

region-fragment

Another property, region-fragment controls the behavior of the last region associated with a named flow. For example how should the region behave if there’s more content left than what will fit in that last region?

The two possible values are auto and break and they work as follows.

  • auto — content flows as it would in a regular content box. It can overflow the container of have its overflow set to hidden or auto, etc.
  • break — content breaks as if it were going to another region even if none exists. If the content fits in the last region there’s no effect.

::region() functional pseudo-element

A pseudo element exists for greater control in styling regions independently. This functional pseudo element can be added to any selector that matches a css region and it takes another selector as its argument.

If you wanted to change the line-height of the text in paragraphs inside region1, but not any other region, you could add the following css:

1  2  3  
#region1::region(p) {    line-height: 1.2;  }

There’s a limited list of properties you can specify for this pseudo element, which you can see on the other side of the previous link.

I wasn’t able to get this property to work as shown above in Canary. It still supports an older syntax, which you can see in the example in the next section.

Example

Because browser support is still so limited instead of linking to a live demo I’ll present an image of my results and share the code I used to get it.

example using regions to layout content

Once again I used the opening paragraph from Jack Kerouac’s On the Road, though I doubled it and broke it up into several paragraphs for this example.

Here’s the html I used minus the text itself and a few paragraph tags to make things cleaner.

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  
<div class="container">   <div id="region1" class="region"></div>   <div id="region2" class="region"></div>   <div id="region3" class="region"></div>   <div id="region4" class="region"></div>   <div id="region5" class="region"></div>   <div id="region6" class="region"></div>    <article>  <h1></h1>  <p class="break"></p>  <p></p><p></p>   </article>  </div>

I’ve create 6 regions and given each a unique id and a common class. In the image above the first 3 regions form the row across the top, region4 takes up the entire second row and regions 5 and 6 comprise the 3rd and last row. These regions contain no content in the html. All the content is inside the article block of code.

First some general css not specific to the regions:

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  
* {    box-sizing: border-box;  }    .container {    max-width: 48em;    margin: 2em auto;    padding-bottom: 10em;    overflow: hidden;  }    h1 {    font-size: 4.5em;    margin: 0 0 1em 0;    font-family: 'myriad pro';  }

Nothing special about the above. I’m showing it just for completeness.

The next bit of code sets up the regions and connects them to the article through a named flow. It also sets up some basic layout for each region.

Note: I’m using the -webkit vendor prefix where necessary below. If you’re testing in IE you’ll naturally need the -ms prefix. Nothing works without a vendor prefix as I write this.

1  2  3  4  5  6  7  8  9  10  11  12  
article {    -webkit-flow-into: article-flow;  }    .region {  -webkit-flow-from: article-flow;    float: left;    width: 33.333%;    height: 300px;    padding: 1em 2%;    border-right: 1px solid #ccc;  }

One thing to note is that I’ve set a height on the regions. Without a set height, the first region can expand to hold everything and so not much interesting will happen. It’s an important consideration with regions.

To adjust the overall layout, I set some css on region4 so it would sit along in its own row and split the row below equally between region5 and region6. I adjusted their heights and added borders to the top and bottom of region4.

1  2  3  4  5  6  7  8  9  10  11  12  
#region4 {    clear: left;    width: 100%;    border: solid #ccc;    border-width: 1px 0 1px 0;    height: 250px;  }    #region5, #region6 {    width: 50%;    height: 200px;  }

Next some background color for region1 and removing the right border on regions 3 and 6.

1  2  3  4  5  6  7  
#region1 {    background: #efe;  }    #region3, #region6 {    border-right: 0;  }

Let’s break the content after the main heading

1  2  3  
.break {    -webkit-region-break-before: always;  }

Note, the above is different from what the spec calls for. There’s an additional region in the property name. I assume this is legacy still in Canary.

Finally I wanted to style some things inside the regions. Again I had to use an older syntax instead of the functional pseudo element.

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  
@-webkit-region #region1 {    h1 {      color: #933;    }  }    @-webkit-region #region5 {    p {      color: #339;    }  }    @-webkit-region #region6 {    p {      color: #339;    }  }

That’s everything I used to create the layout you see at the top of this section. Other than some time finding the older syntax, it didn’t take long to create.

Because you have to set explicit heights before regions show off what they can do, I don’t know that we’ll use them for entire layouts, however I think they might work nicely for the opening of an article. Imagine in my example region4 (the full width row) was the last. You’d create an interesting open and then have the rest of your content below.

Regions will also come in handy for art directed pages or any page where you’ll know the content in advance and that won’t be subject to arbitrary changes.

You can find examples below, both from Adobe. The first links to a number of examples. The second shows what you might achieve combining regions with exclusions and shapes.

Summary

As I’ve said throughout these posts on future css, regions aren’t anything we’re going to be using today or tomorrow, but somewhere down the road they’ll mostly likely be a part of your toolbox. They offer a nice way to control how elements flow through your design and they allow for more complex and richer layouts in a relatively pain free way.

You can experiment with regions now if you want. IE10+, Safari 7+ and Chrome Canary with flags set will all allow you to play around in some fashion.

The post The CSS Regions Module — Control Where Content Flows appeared first on Vanseo Design.