Five Simple Steps A Pocket Guide CSS3 layout modules by Rachel Andrew 2 3 A Pocket Guide to CSS3 Layout Modules by Rachel Andrew Published in 2012 by Five Simple Steps Studio Two, The Coach House Stanwell Road Penarth CF64 3EU United Kingdom On the web: www.fivesimplesteps.com and: www.rachelandrew.co.uk Please send errors to errata@fivesimplesteps.com Publisher: Five Simple Steps Editor: Owen Gregory Tech Editor: Nathan Ford Production Manager: Jo Brewer Art Director: Nick Boulton Design: Nick Boulton, Colin Kersley Copyright © 2013 Rachel Andrew All rights reserved. No part of this publication may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopy, recording or any information storage and retrieval system, without prior permission in writing from the publisher. ISBN: 978-1-907828-09-6 A catalogue record of this book is available from the British Library. … Foreword 6 I have been using CSS ever since it first became a practical possibility in browsers and I was a fairly early adopter of CSS for layout. I have always enjoyed playing with the latest features, despite the inevitable frustration of dealing with lack of support in browsers. In the last few years we have seen a great leap forward in what we can achieve with CSS – web fonts, gradients, shadows and media queries are now part of our everyday toolkit. CSS layout itself, however, has moved on little. Developers have experimented with using display:table and display:inline-block for layout, in order to mitigate the limitations of layouts based on absolute positioning and floats. Yet, these methods seem as much like hacks as those they try to replace, and come with their own problems. The future of CSS layout looks far brighter. In this little book I will cover some of the exciting modules that are part of the CSS3 specification. They promise a future where we can lay out elements to a grid and easily achieve the ambitions of equal height columns or spreading content evenly across a page. With the help of specifications put forward by companies such as Adobe, which knows a thing or two about layout, we can finally take control of how things are displayed in a web browser, without adversely affecting the use of that content in other ways. I have used examples in this book that have some implementation in one or more browsers, so you can try them out. Some of these modules are at a relatively early stage and implementations may change. Remember that you can give feedback to the standards process yourself. This is our web and we 7 should be keen to engage with those who are involved in creating the specifications we use. If you use any of these techniques in production you will need to ensure that your pages still display well for users whose browsers do not support that particular module. I don’t want to spend much time dealing with browser compatibility issues; however, at the end of each section you will find some tips and suggestions. A note on vendor prefixes Almost everything I cover in this book will require vendor prefixes in some or all browsers. With the more stable modules – multicolumn layout and flexible box layout (flexbox) – I use Lea Verou’s -prefix-free script to show you the standard properties and still have working examples in browsers. I would suggest that in production you either add the prefixed versions to your CSS or use a CSS preprocessor to compile them into your final CSS. With the very new modules that only have support in one browser, and where the specification is highly likely to change, I have used the prefixes for the browser that I have tested the examples in. By the time this book is published it may be that other browsers will have added support with their prefixes. Owing to the experimental nature of these implementations, however, they may work differently. You should test and use the prefixes for other browsers where available, plus the non-prefixed version in production. 1 Multicolumn layout CSS3 multicolumn layout has been a tantalising possibility for some years now. However, with lack of support in Internet Explorer it hasn’t been taken up as much as it deserves. With IE10 supporting these properties, and its usefulness in creating responsive designs, I hope we will very soon see it used more. This module is the most mature and has the most browser support of all the modules I cover in this book, so it’s a great place to start our exploration of all that is new in CSS layout. 10 Multicolumn layout makes it possible to arrange content in columns, in the same way that content flows in a newspaper. You can take a container in your document and state that you want it to be arranged into columns, and the browser will make it so. If you specify the number of columns that you want the content arranged into, the browser will work out the width of each column so that it will fit into the parent box. If you specify a width for the columns then the browser will display as many columns as it is able, maintaining that width for each. Example: Specifying column-width - view example .col-wrapper { column-width: 220px; } Setting column-width 11 Specifying a column-width means that the browser will fit as many columns into the container as possible, using the specified width as the ideal width. You may notice that when we specify the width for columns we don’t in fact get that exact width. The columns will always be even in the space, so the browser will work out how many columns can fit as close to the specified width as possible. The specification says: “[The column-width value] describes the optimal column width. The actual column width may be wider (to fill the available space), or narrower (only if the available space is smaller than the specified column width). Specified values must be greater than 0.” Therefore, when setting the width you should specify the optimal column width, though it may be that the actual width is different – especially in a flexible design. Example: Specifying column-count - view example You can also specify how many columns you want and then let the browser decide how wide they should be, using column-count. .col-wrapper { column-count:3; } Setting the column-count to 4 12 Controlling gutters You can also see in my examples that the columns do not butt up against each other: there is a gap between each column. In the multicolumn layout specification this gutter is controlled by the column-gap property. If you set column-gap to zero there will be no space between columns and the text will run together. The specification suggests that user agents use a value of 1em as the default for this property; however, if you want to ensure your gutters are a certain width to line up with a grid, then you should set a value yourself. Example: Setting the column-gap property - view example .col-wrapper { column-width: 220px; column-gap: 1.5em; } Styling your columns Column styling is relatively limited in the current specification, although there is a note in the working draft stating that “[f]uture specifications may add additional functionality. For example, columns of different widths and different backgrounds may be supported.” At present you cannot style columns individually. 13 There is no way to set margins and padding on a column, or set the width or background colour of an individual column. We can, however, use a rule to divide our columns. This is achieved by way of column-rule properties: • column-rule-style • column-rule-width • column-rule-color These properties behave in the same way as border-style, borderwidth and border-color and can also be written as shorthand using the column-rule property: column-rule: [width] [style] [color]; The column rule is placed centrally in the area created for the column-gap. To change the space on either side of the rule, adjust the value you used for the column-gap property. If the rule is wider than the available gap then it will start to overlap text in the columns – it does not take up any space itself. 14 Example: Using column-rule - view example .col-wrapper { column-width: 220px; column-gap: 2em; column-rule: 2px dotted #ccc; } Setting a 2-pixel dotted rule between the columns 15 Column span If you would like an element to span all columns then you can give the property column-span a value of all. In the following example, I want the main h1 heading to span across all columns. Example: Causing the h1 to span all columns - view example .col-wrapper h1 { column-span: all; padding: 0 0 .5em 0; } The current specification gives only two values for column-span, all or none. Using column-span to cause the heading to span across all columns 16 Column breaks When using multicolumn layout you have control over how columns break. This can be useful where there are elements that you would prefer not to end up wrapped into a new column, or when you want to make sure a certain element always starts a column. Example: Avoiding breaks inside paragraphs and before blockquotes - view example .col-wrapper p { break-inside: avoid; } .col-wrapper blockquote { break-before: avoid; } Printing and paged media The specification states that multicolumn elements should not continue on to the next page. It would be very annoying if you had to read down one column, onto the next page and then back to the first page to start reading at the top of the next column! You can also determine how the content behaves when a page break falls in the middle of a paragraph or other element – just as you can control breaks when the content wraps into new columns. The properties avoid-page and avoid-column give you finer control. If you are happy for paragraphs to break across columns but not pages, in the example above you could use break-inside: avoidpage rather than just avoid. 17 Responsive design The multicolumn layout module is useful for responsive design as the specification means that the columns are responsive by default. As we have seen, the column width setting only sets the most desirable width for the column: the browser is left to work out the actual width. An image placed inside a column will be constrained by the column width, so the standard method of scaling down an image by using max-width will work within columns. If you do not set maxwidth: 100% on an image, and the image is wider than the column, then the browser will crop the image. This behaviour is the same for any element within a column that is wider than the current column width. Example: Images are constrained by the columns - view example The images are constrained by the column widths 18 You shouldn’t think of this module as being useful for just creating something like a newspaper layout. The following example shows a layout comprising a number of boxes and images arranged using multicolumn layout. Example: Boxes and images - view example Multicolumn layout can be used to lay out boxes 19 These will display in a single column on narrower windows without you needing to write any extra code 20 Browser tips At the time of writing, multicolumn layouts are supported in several browsers. You may need to use a prefixed value, and in some cases not all properties will work. For the most up-to-date browser information see Can I Use. If a browser does not support multicolumn layout then it will simply ignore it, making this module safe to use. A non-supporting browser will render the content in a single column, which in most cases is perfectly acceptable – I would suggest you don’t attempt to polyfill this module. 21 2 CSS flexible box layout The CSS flexible box layout module, commonly referred to as flexbox, gives us a brand new layout mode in CSS – flex layout. It has been designed to make it easier to layout complex applications and webpages. In this section, I take a look at some of the main layout problems flexbox can solve. 24 Spacing items evenly Taking a group of items and spacing them along an axis is a task that has traditionally been rather difficult in web design. Floated elements need a width, yet each one might be a different width and getting them all to fit on a single line with equal spacing usually involves some JavaScript. Flexbox makes this task easy. In my markup I have a list that contains my navigation. Example: Simple flexbox usage - view example <nav class="mainnav"> <ul> <li><a href="">Introductory</a></li> <li><a href="">The First Cat Show</a></li> <li><a href="">Habits</a></li> <li><a href="">Trained Cats</a></li> <li><a href="">Usefulness of Cats</a></li> </ul> </nav> I would like these items to be spaced evenly as horizontal navigation. Using flexbox, this is as simple as setting them to display:flex and deciding whether I want space around or between the elements. 25 Example: Simple flexbox usage - view example nav ul{ margin: 0; padding: 0; list-style: none; display: flex; justify-content: space-between; } The navigation as a row with equal space between each item Had we set the value of justify-content to space-around then the space would have been added all around each element equally, meaning that instead of being flush to the outside edges of the container, there would be some space before the first and after the last element. 26 The navigation as a row with equal space around each item The simple example above uses some default behaviour of flexbox. The items here have been displayed as a row. This is the default behaviour and is equivalent to setting the property flex-direction to row. The flex-direction property can have one of four values: row; row-reverse; column; and column-reverse. These enable you to display the items in a row, or reverse their order in a row; and similarly in a column, or a column with the order reversed. nav ul{ margin: 0; padding: 0; list-style: none; display: flex; justify-content: space-between; flex-direction: row-reverse; } 27 Using flex-direction:row-reverse to display the items in reverse order Another interesting aspect of flexbox is that it enables you to create equal height boxes, even if the content of some boxes is longer than others. The default value of the property align-items is stretch. This stretches each item in the group to the height of the tallest. You can see this in action in our navigation if we make the window narrower, so some items wrap on to two lines. The borders of all items remain the same height. Items in the group all take the height of the tallest item 28 The property align-items can also take the following values: • flex-start • flex-end • center • baseline • stretch To understand how these work you need to realise that flexbox has a concept of two axes: the main axis, along which items flow; and the cross-axis. By setting flex-direction to row or column you determine your main axis and whether that flows left or right, up or down; the secondary, or cross-axis, then runs across it. If the flex-direction is row then your main axis runs left to right. Setting align-items to flex-end means they will not take on the full height and shorter items will be aligned to the bottom of the box. Our example with the align-items property given a value of flex-end 29 Wrapping flexbox rows In the example we have been working with, if we make the viewport narrower, then the text in the items wraps. Ultimately, however, we will run out of room and the box will become wider than the available area. One way to deal with this is to set the items inside our flexbox element to wrap. Whether or not items are allowed to wrap is decided by the flex-wrap property, which can take values of wrap, nowrap and wrap-reverse. The default, if you do not set a value for flex-wrap, is nowrap. Example: Wrapping items - view example nav ul{ margin: 0; padding: 0; list-style: none; display: flex; justify-content: space-between; align-items: stretch; flex-direction: row-reverse; flex-wrap: wrap; } 30 The items wrap if we add flex-wrap:wrap to the container You can see now, though, that the spacing between items is less desirable. You can fix this by getting the elements themselves so stretch and fill some space. We can do that by setting the property flex to auto on the items themselves – in this case I add this property to the li element. 31 nav li { border: 1px solid #999; border-radius: 2px; flex:auto; margin: 0 1em 1em 0; text-align: center; } The elements wrap on to two lines and take up all of the space. 32 Using the flex property Setting the value of flex to auto on an item makes the items fit nicely within a space, but there are other ways to use this property. In this example I have three boxes containing information about long-haired cat breeds. These are marked up with a class of box, and I have also added a class to identify each box individually. Example: Three boxes - view example <div class="boxes"> <div class="box box1"> <h2>The Angora</h2> <p>… </p> </div> <div class="box box2"> <h2>The Persian Cat</h2> <p>… </p> </div> <div class="box box3"> <h2>The Russian Long-haired Cat</h2> <p>… </p> </div> </div> 33 To display these boxes in a row I am going to make the container – boxes – a flex element and then to each box inside I will assign a value to the flex property of 1. This gives each box an equal width within the space. .boxes { display: flex; flex-direction: row; flex-wrap: wrap; align-items: stretch; justify-content: space-between; } .box { border: 1px solid #999; border-radius: 5px; flex: 1; margin: 0 1em 1em 1em; padding: 10px; } The three boxes are of equal width within the container 34 We might want one of the boxes to take up more space than the others, but still have the width calculated according to the available space. The third box in the markup has a class of box3. If I give box3 a flex value of 2 it will now take up twice as much space as boxes that are set to flex:1. .box3 { flex: 2; } The third box takes up twice the width of the other boxes 35 Ordering flex items We have already seen that it is possible to reverse the order in which items are shown. You can also target individual items and set an order for them with the order property. By giving each of my items an order property I can easily move box3, the wider box, to the centre, by giving it a value of 2. .box1 { order: 1; } .box2 { order: 3; } .box3 { flex: 2; order: 2; } Using the order property to change the order of our items 36 The items remain exactly as they were in the HTML. This means you can order your markup so it makes sense in terms of accessibility and how it would be read out by a text-to-speech device. You can then use the order property to create a visual layout that works best. Responsive design Flexbox is a great addition to our toolkit when we create responsive designs. Being able to wrap rows and flex items to fit the available space means that with very little effort simple designs can be responsive. Once you start to mix flexbox with media queries you can achieve far more complex layouts. Being able to display items independently of source order makes creating a different arrangement of elements for different screen sizes possible. You can also easily switch flex-direction as shown in the example below. We can display our navigation as a column until we get to a width of 700 pixels, at which point we switch to displaying it as a row. nav ul{ margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; 37 justify-content: space-between; align-items: stretch; } @media only screen and (min-width: 700px) { nav ul { flex-direction: row; } } Browser tips Flexbox is a good example of how specifications in their early stages can change. There is a lot of out-of-date information about flexbox available because the implementation has changed so much from the initial proposal. When searching for more information on flexbox, take note of this CSS Tricks article on how to check if the advice you are reading is current. While it would be possible to polyfill a lot of the flexbox functionality using JavaScript, you may also find that you can allow browsers to fall back to a linear state if they do not support flexbox. For example, our three boxes display as in the figure below in a nonsupporting browser. 38 Flexbox items linearized in a browser with no flexbox support Falling back to a linearised display is easier if you are just using the module for small interface elements rather than your entire layout. Another possibility would be to use Modernizr to detect flexbox support and fork your CSS with flexbox and non-flexbox alternatives. 39 3 CSS grid layout The CSS grid layout module is still very much a work in progress and was proposed by Microsoft. There is an implementation of the current proposal in Internet Explorer 10, on which I am basing these examples. 42 Grid layout seeks to solve the problems of laying out complex web pages, a task which until now we have had to use floats and positioned elements for. It also allows us to separate how things are laid out from the source order – something we saw in our exploration of flexbox. I really like the grid layout proposal and I hope after seeing these examples you will too. Creating the grid To start laying items out on a grid we first need to create the grid on a parent element. We do this by setting the display property to grid (I am using the –ms prefix) and then setting the number of columns and rows our grid will have. Example: A simple grid layout - view example .wrapper { display: -ms-grid; -ms-grid-columns: 200px 20px auto 20px 250px; -ms-grid-rows: auto 1fr; } The CSS above creates a grid inside the element with a class of wrapper. The grid will have five columns: a 200-pixel wide sidebar; a gutter of 20 pixels; a central column that will stretch to take up any available space; another 20-pixel gutter; and a final 250-pixel 43 wide column. So, this is a very simple layout with two fixed-width columns and a flexible central column. For the rows, I have set my first row as auto – it will expand to fit whatever we put into it – then a second row of 1fr. This is actually a fraction value, but in this case it will mean that this row takes up whatever space we have left – it’s a two row grid. We can now pop some items into the grid. My markup looks like this: <div class="wrapper"> <nav class="mainnav"> <ul> <li><a href="">Introductory</a></li> <li><a href="">The First Cat Show</a></li> <li><a href="">Habits</a></li> <li><a href="">Trained Cats</a></li> <li><a href="">Usefulness of Cats</a></li> </ul> </nav> <h2 class="subhead">Usefulness of cats</h2> <article class="content"> <p>…</p> </article> <blockquote class="quote"> <p>….</p> </blockquote> </div> 44 To put the navigation into the left static column, the article in the centre, and the quote on the right I can do the following: .mainnav { -ms-grid-column: 1; -ms-grid-row: 2; } .subhead { -ms-grid-row: 1; -ms-grid-column:3; } .content { -ms-grid-column: 3; -ms-grid-row: 2; } .quote { -ms-grid-column: 5; -ms-grid-row: 2; } All we do is say which column and row we want to place the content into. Remember that the gutters count as columns too, so the main column is actually column 3 and the right column is column 5. 45 The simple grid layout example When trying to understand grids I have found it useful to visualise the process as creating an old-fashioned table for layout, except doing it in CSS. I then place my items inside the table cells. However, unlike tables for layout, by defining the grid in the CSS we are free to redefine it to suit the environment in which the content is displayed. This means that grids can be a powerful tool in the future of responsive design. 46 Grids and responsive web design I’m now going to take a look at a slightly more complex, and probably more realistic example to demonstrate how grid layout can be used for responsive design. My document is very simple: a div with a class of wrapper; then five sections marked up with a class of box containing some information; and an image from our Victorian book about cats. For simplicity, I have added a second class so that I can easily target each content area with CSS. Example: A responsive grid layout - view example <h1 class="title">Extracts from "Our Cats, by Harrison Weir"</h1> <div class="wrapper"> <div class="box content1"> <h2>The first cat show</h2> <p> …</p> </div> <div class="box content2"> <h3>The Angora</h3> <p>… </p> </div> <div class="box content3"> <h3>The Persian Cat</h3> <p>… </p> </div> 47 <div class="box content4"> <h3>The Russian Long-haired Cat</h3> <p>...</p></div> <div class="box picturebox"> <figure><img src="fluffy.jpg" alt="Fluffy the cat" /> <figcaption>Fluffy, the cat</figcaption> </figure> </div> </div> With just some basic CSS for styling, we end up with a linearised design as shown in the figure below. Our starting point 48 We now need to declare our grid, and I’ll do this by adding to the properties for .wrapper. .wrapper { width: 90%; margin: 0 auto 0 auto; display: -ms-grid; -ms-grid-columns: 1fr (4.25fr 1fr)[6]; -ms-grid-rows: (auto 20px)[4]; } I have set display to -ms-grid, declaring this element contains a grid layout. I have set up my columns using a shorthand syntax for multiple columns. By putting a set of columns in round brackets followed by a number in square brackets, we say that we want to repeat this column pattern n times; in this case, I want these two columns to be repeated six times. I use the concept of fractions to create a flexible grid. The gutters between my columns are to be 1 fraction unit; the columns themselves 4.25 fraction units. I then use the same syntax for rows, creating a row that will expand to fit the content followed by a 20-pixel gap between rows four times. If you refresh your page after adding this CSS you will find that the entire column has collapsed. This is because everything is now trying to fit into row 1, column 1 as we haven’t provided any positioning information. Once you have declared a grid on an element, all of its child elements need to be placed on the grid. 49 After declaring a grid on a parent element all child elements will display in row 1, column 1 I’m going to start by positioning my elements as I want them to display for narrower screen sizes. As people using such devices are likely to be reading from the top down, I’m going to display things pretty much in the order they are in the source – which I have structured in terms of content priority for screen readers. In this new world of separated source and layout I don’t need to worry about where things are in the source, as we will see. 50 .content1 { -ms-grid-row: 1; -ms-grid-column: 2; -ms-grid-column-span:12; } .content2 { -ms-grid-row:3; -ms-grid-column: 2; -ms-grid-column-span:5; } .content3 { -ms-grid-row:3; -ms-grid-column:8; -ms-grid-column-span:6; } .content4 { -ms-grid-row:7; -ms-grid-column: 2; -ms-grid-column-span:12; } 51 .picturebox { -ms-grid-row:5; -ms-grid-column: 2; -ms-grid-column-span:12; } This all looks fairly straightforward. I now choose which row I want to put my items into – remember that the 20-pixel gaps are rows, so we should place items into the odd-numbered rows. I then set the starting column for each area and set how many columns it should span. Most of my boxes are full-width, but I have split content2 and content3 into two columns. This now displays in the browser as a simple layout. The layout on narrower screens 52 I am now going to add my first media query, and make some changes to the layout once the browser window reaches 700 pixels wide. @media only screen and (min-width: 700px) { .wrapper { -ms-grid-columns: 1fr (4.25fr 1fr)[9]; -ms-grid-rows: (auto 20px)[5]; } .content1 { -ms-grid-row: 1; -ms-grid-column: 2; -ms-grid-column-span:17; } .content2 { -ms-grid-row:3; -ms-grid-column:8; -ms-grid-column-span:5; } .content3 { -ms-grid-row:3; -ms-grid-column:14; -ms-grid-column-span:5; } 53 .content4 { -ms-grid-row:3; -ms-grid-column: 2; -ms-grid-row-span: 3; -ms-grid-column-span:5; } .picturebox { -ms-grid-row:5; -ms-grid-column: 8; -ms-grid-column-span:11; } } For this wider layout, I have redefined my grid to have more columns and an additional row. My first content area remains at full-width at the top of the layout. However, I have now split the other content into three columns, making one of them span across two rows, the other two becoming half–height, and dropping the image in below them spanning both areas. 54 The more complex layout for screens wider than 700 pixels 55 Finally, I can rearrange my content again for wider screens with a media query that kicks in at 940 pixels wide. @media only screen and (min-width: 940px) { .wrapper { -ms-grid-columns: 1fr (4.25fr 1fr)[16]; -ms-grid-rows: (auto 20px)[3]; } .content1 { -ms-grid-row:1; -ms-grid-row-span: 3; -ms-grid-column: 20; -ms-grid-column-span:13; } .content4, .content2, .content3 { -ms-grid-row:1; } .picturebox { -ms-grid-row:3; } } I have redefined the grid again, this time ending up with a pretty standard grid based on the 960 grid system. I can then move my content area to create a layout with three narrow columns, one wider column and the image sat under two of the narrower columns. 56 The wider screen layout The real beauty of this module is the ease with which we can shift content around in the layout without changing the source markup. I also think the syntax of this module is pretty easy to understand once you have grasped the model – certainly for old-school folk like me who remember using tables for layout! 57 Browser issues As already explained, this module has currently only been implemented in IE10, since the specification itself was proposed by Microsoft. If you are developing Windows apps you may already be able to use it in that context, though I really hope we’ll see implementations in other browsers soon. 4 CSS regions The final two sections of this book discuss some very interesting new proposals authored by Adobe and Microsoft. While these are at an even earlier stage than grid layout, they enable layouts that until now have been impossible and are worth our time when exploring all that is new in CSS layout. 60 The CSS regions specification creates an advanced model for content flow. We can specify regions of our document that content can flow into for display purposes – even if these regions are not next to each other in the document order. This sounds a bit strange in a web context – however, this kind of layout is often used in print design, in particular in magazines and newspapers. CSS regions does not provide any new methods for layout, and so can be used with any existing or future ways to position elements. To demonstrate how CSS regions work, it is easiest to look at an example. At the time of writing, the only browser that supports this is Chrome Canary with experimental WebKit features turned on. If you have a copy you should be able to play with the example code. Here is the HTML. I have an article element that contains the entire content of my article. I have then added a number of empty elements at the bottom of the document. <div class="wrapper"> <article class="main"> <h2>Usefulness of cats</h2> <p>…</p> <p>…</p> </article> <div class="region1 article-regions"></div> <div class="regionwrapper"> <div class="region2 article-regions"></div> <div class="region3 article-regions"></div> 61 <div class="region4 article-regions"></div> </div> <div class="region5 article-regions"></div> </div> The article contains the content that I want to lay out, and the empty elements will become containers for that content. First, I need to use a new CSS property flow-into (using a –webkit prefix) on the container for my content. The value article-thread is a name I have chosen for this content; it can be anything you want. .main { -webkit-flow-into: article-thread; } Once you do this, the content will disappear as you haven’t yet specified anywhere for it to go. Each of my empty elements has a class of article-regions, so I can now target that class as being the recipient of the content. .article-regions { -webkit-flow-from: article-thread; } This time, we are using the new flow-from property with a value that matches the name we used earlier. If you now refresh your page you will see that the content reappears. It is now flowing into the first of our regions. With the content flowing, we can start to lay it out by applying CSS to the specific regions. 62 .region1 { height: 10em; } .regionwrapper { display: flex; flex-direction: row; } .region2 { flex: 1; padding: 10px; height: 40em; border-right: 1px dotted #ccc; } .region3 { flex: 1; padding: 10px; height: 40em; border-right: 1px dotted #ccc; background-color: #efefef; } .region4 { flex: 1; padding: 10px; height: 40em; } .region5 { padding: 1em 0 0 0; margin: 1em 0 0 0; 63 border-top: 1px dotted #ccc; height: auto; } My region region1 now has a height of 10em. Once that height is reached, the content has to go somewhere else, so it flows into the next region. The next three regions have been positioned using flexbox into a flexible row of three columns, so my content flows into those. They have a fixed height, so again my content runs out of room and then has to flow into the final region which has a height of auto and so allows the content to display until it finishes. The complex layout is achieved without needing to break up the actual content in the document. 64 If I change my mind and want to insert something else into the middle of this content, I can. In the example below I have taken the article-regions class off the middle flexbox column, so the content no longer flows into it. I can now use it for a nice picture of a cat and a quote – unrelated to the content flowing around it. The content ignores the central column as it is no longer a container for that content flow. 65 Browser tips We are looking at the sharp end of emerging CSS modules here, with support for regions only appearing in experimental form in WebKit browsers. This isn’t a technique you’re likely to be able to use in production yet. I think the possibilities for CSS regions are really exciting however, and if we as developers test and request support for a module, it is far more likely to become included in browsers. 5 CSS exclusions If you have ever needed text to flow around a shape, or wanted to cut out a shape in the middle of content, then you will be interested in the CSS exclusions and shapes module, proposed by Adobe. An earlier specification exists which referred to positioned floats, but this has been superseded by the current working draft. 68 We are all familiar with floats in CSS. The simplest example might be floating an image to allow text to flow around it. However, floats are fairly limited when used in this manner; the floated item always rises to the top, so while we can float an image left and wrap text to the right and below it, there’s no way to drop an image into the middle of the document and flow text all the way around, or position it at the bottom and let text flow round the top and side. It is this issue that the first part of the exclusions and shapes module solves, and as this is supported in IE10, as well as experimental WebKit builds, we can see an example in action. My markup is a simple block of text, marked up as an article with a class of main. Following this, I have a div containing an image of Fluffy, the cat. I’d like the image to appear floated inside the copy with the text wrapping around. <div class="wrapper"> <article class="main"> <h2>Usefulness of cats</h2> <p>…</p> </article> <div class="exclusion"><img src="fluffy.jpg" alt="Fluffy the cat" /></div> </div> 69 First, I am going to create a grid as we did earlier. Unlike floats, an exclusion needs to be positioned (hence the earlier name of positioned floats) and, as I am using IE10 to demonstrate this example, I can use the grid layout support for the positioning. My grid creates a three-column, three-row grid, and I then set my article to span all three rows and columns. Finally, I place my div with a class of exclusion into the central area. As this div comes after the article in the source order it will display on top of the text. .main { -ms-grid-column: 1; -ms-grid-row: 1; -ms-grid-row-span: 3; -ms-grid-column-span: 3; padding: 0 0 2em 0; } .exclusion { -ms-grid-row:2; -ms-grid-column:2; height: 160px; width: 200px; padding: 10px; } 70 The image sat on top of the text, taking its place on the grid To create the exclusion, a floated image with text wrapped around, I just need to set the wrap-flow property on .exclusion. .exclusion { -ms-grid-row:2; -ms-grid-column:2; height: 160px; width: 200px; padding: 10px; -ms-wrap-flow:both; } 71 The value both means that the text will wrap around on both sides of the exclusion. The image now floats with text continuing on either side Wrapping around rectangular shapes is not the only thing covered by the CSS exclusions and shapes module. Also at a very early stage in browser implementation is the possibility of wrapping text around and inside shapes. If you have Chrome Canary with experimental WebKit features turned on then you should be able to take a look at the examples posted by Adobe, or even have a go 72 at creating your own. This is still very new stuff and reasonably complex, although as it is being tested in WebKit it may very well be making its way to a browser near you soon. Browser support The wrap-flow functionality will be very useful in providing more control over text wrapping around elements in a document and, with care, could start to be used fairly quickly as browsers begin to support it. By placing items in the source carefully you could simply fall back to alternative positioning in non-supporting browsers, or use JavaScript feature detection by way of something like Modernizr to check for support and offer an alternative positioning scheme. Even shapes, once implemented in some mainstream browsers, could be used with care. As long as the flowing of text is a niceto-have feature and not something integral to your design, there is no reason why you could not add these finishing touches for those browsers that support them – especially if you know that the audience visiting your site is likely to use such browsers. 73 = Conclusion Working through and testing these modules has been exciting and interesting, and I hope that I have encouraged you to take a look at what is possible now and what might be coming soon for CSS. Learning about shiny new things that we can’t use yet can be frustrating, but it is also important if we want to move forward. Participation in creating and testing these specifications is not something only for browser makers and big companies. If we want to see these modules in browsers then we – the regular web designers and developers who use these features – can get involved too. Take a look at Move the Web Forward: there are links there to help you get involved with the standards process in a variety of ways.