Uploaded by Geoffroy Gaborieau

CSSLayoutModules

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.