CSS Template Layout Module

W3C Working Draft 29 November 2011

This version:
Latest version:
Previous version:
Bert Bos (W3C)
César Acebal (University of Oviedo)


Image: four elements move to four   slots in a template

A grid with four slots defined by ‘display: "aaaaaaa" "bccccdd"’.

CSS is a simple, declarative language for creating style sheets that specify the rendering of HTML and other structured documents. This module contains CSS features to describe layouts at a high level, meant for tasks such as the positioning and alignment of “widgets” in a graphical user interface or the layout grid for a page or a window.

A layout grid or “template” defines one or more “slots” that an element's content can flow into. This allows elements to have complex shapes and it allows the visual order to be different from the order of the elements in the source document.

A ‘::slot’ selector allows elements to be styled differently based on which slot they appear in.

Status of this document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

The (archived) public mailing list www-style@w3.org (see instructions) is preferred for discussion of this specification. When sending e-mail, please put the text “css3-layout” in the subject, preferably like this: “[css3-layout] …summary of comment…

This document was produced by the CSS Working Group (part of the Style Activity).

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This draft is related to the drafts about positoning with grid units (‘fr’), creating and naming grids and regions [CSS3-GRID-LAYOUT], flexible GUIs [CSS3-FLEXBOX], and tables [CSS3TBL]. The CSS Working Group is considering combining some or all of these into a single specification with all matrix-based layouts.

The section on “CR exit criteria” lists some conditions for this specification to become a W3C Recommendation.

Issues on this draft are mentioned in the text itself (like this) and/or in the on-line Tracker under “Details on Product CSS3 Template Layout.”

Table of contents

1. Dependencies on other modules

This CSS3 module depends on the following other CSS3 modules:

Add to the above all the properties that are allowed on slots (see “The ‘::slot()’ pseudo-element”).

It has non-normative (informative) references to the following other CSS3 modules:

See section 1.4.2 of CSS level 2 [CSS21] for the grammar and other notations that this specification uses in property definitions.

2. Introduction

(This section is not normative.)

Image: four elements move to four   slots in a template

Four regions, called a, b, c and d, each receive a part of a document

The styling of a Web page, a form or a graphical user interface can roughly be divided in two parts: (1) defining the overall “grid” of the page or window and (2) specifying the fonts, indents, colors, etc., of the text and other objects. The two are not completely separate, of course, because indenting or coloring a text influences the perceived grid as well. Nevertheless, when one separates the parts of a style that should change when the window gets bigger from the parts that stay the same, one often finds that the grid changes (room for a sidebar, extra navigation bar, big margins, larger images…), while fonts, colors, indents, numbering styles, and many other things don't have to change, until the size of the window becomes extreme.

The properties in this specification work by associating a layout policy with an element. Rather than letting an element lay out its descendants in their normal order as inline text or as blocks of text (the policies available in CSS level 1), the policy defined in this module, called template-based positioning, gives an element an invisible grid for aligning descendant elements.

Because layouts on the Web have to adapt to different window and paper sizes, the rows and columns of the grid can be made fixed or flexible in size.

The typical use cases for these properties include:

Template-based positioning is an alternative to absolute positioning, which, like absolute positioning, is especially useful for aligning elements that don't have simple relationships in the source (parent-child, ancestor-descendant, immediate sibling). But in contrast to absolute positioning, the elements are not positioned with the help of horizontal and vertical coordinates, but by mapping them into slots in a table-like template. The relative size and alignment of elements is thus governed implicitly by the rows and columns of the template. A template doesn't allow elements to overlap, but it provides layouts that adapt better to different widths.

Call it a “slot” or rather a “region”?

The mapping is done with the ‘position’ property, which specifies in this case into which slot of the template the element goes. The template itself is specified on the ‘display’ property of some ancestor of the elements to remap.

In this example, the four children of an element are assigned to four slots (called a, b, c and d) in a 2×2 template. (All mark-up examples in this specification are HTML fragments, unless otherwise stated.)

Image: sample rendering

Each element occupies one slot. In this template, all slots have the same size.

<style type="text/css">
  dl { display: "ab"
                "cd" }
  #sym1 { position: a }
  #lab1 { position: b }
  #sym2 { position: c }
  #lab2 { position: d }
  <dt id=sym1>A
  <dd id=lab1>A is een aapje
  <dt id=sym2>B
  <dd id=lab2>B is de bakker

Templates can also help with device-independence. This example uses Media Queries [MEDIAQ] to change the overall layout of a page from 3-column layout for a wide screen to a 1-column layout for a narrow screen. It assumes the page has been marked-up with logical sections with IDs.

@media all
  body { display: "aaa"
                  "bcd" }
  #head { position: a }
  #nav { position: b }
  #adv { position: c }
  #body { position: d }
@media all and (max-width: 500px)
  body { display: "a"
                  "c" }
  #head { position: a }
  #nav { position: b }
  #adv { display: none }
  #body { position: c }

Elements can be positioned this way, but not made to overlap, unless with negative margins. Here is how the “zunflower” design of the Zen Garden could be done:

#container { display: "abc" }
#intro { position: a; margin-right: -2em; box-shadow: 0.5em 0.5em 0.5em }
#supportingText { position: b; box-shadow: 0.5em 0.5em 0.5em }
#linkList { position: c }

Template-based positioning borrows some concepts from table layout, in particular the idea of aligning elements in rows and columns, so that they constrain each other's size. But there are also differences. This example shows some of them. Assume this document fragment:

<div class=group>
 <div>aa aa aa aa aa aa</div>
 <div class=menu>ccccc</div>

We can lay it out as three columns, as the following illustrations show. The style sheet would contain the following.

.group {display: table}
.group > div {display: table-cell}

[Three unequal cells]

Example of rendering with a table.

We can also use a template, in which case the style sheet would contain this:

.group {display: "abc"}
.group > div {position: a}
.group > div + div {position: b}
.group > div + div + div {position: c}

By default, the table is as wide as needed to fit its contents. To make sure it is as wide as its containing block, we need to add

.group {display: table; width: 100%}

That is not needed for the template, but, on the other hand, if we want the template to fit its contents, we would need to say so:

.group {display: "abc"; width: fit-content}

(See [CSS3BOX] for the definition of the ‘width’ property.) The columns of the template are by default all the same size. The columns of the table satisfy certain constraints, but the exact size is not defined. We can make them all the same by adding a rule (see [CSS3TBL]):

.group {display: table; width: 100%; table-layout: fixed}

[Three equal cells]

Example of rendering with equal columns.

In both styles, we can set a column to a certain size:

div.menu {width: 3em}


.group {display: "abc" * * 3em}

[Two equal cells, third is 3em wide]

Example of rendering with a fixed third column and the other two columns of equal width.

If there is an unknown number of columns (children of the div.group element), the style sheet for the table model will automatically take them into account. The style sheet for the template model, however, creates a template of exactly three columns and can't handle tables with an unknown number of columns. The extra elements will be added into the default slot (in this case the ‘a’ slot).

In both models, elements can have borders, but only in the table model can borders be collapsed, which makes setting borders a little easier in the table model:

.group {display: table; border-collapse: collapse}
.group > div {border: solid}


.group > div {border: solid; border-left: none}
.group > div:first-child {border-left: solid}

In the template model, the order of the elements is explicit, and thus it is possible to reverse the order of the columns:

.group > div {position: c}
.group > div + div {position: b}
.group > div + div + div {position: a}

[Different contents for the cells]

Example of rendering with the contents of the three columns reversed: the third element is shown in the first slot and the first element in the third slot.

In the table model, the order of the rows and columns is given by the document source and thus can't be changed.

This example shows a way to move notes to the end of a section. “Notes” in this example refers to elements in HTML with a class of “note”. A fragment of HTML such as

<div class=section>
  <p>The balubious coster of the fifth secter<span
    class=note> The sixth secter coster is a difter
    manon.</span> of The Rollow Carpug mentizes a costernica.

with this style sheet

div.section {
    display: "@" available
             "F" available}
.note {
    position: F;
    content: counter(note) ".\A0" contents;
    counter-increment: note;
    font-size: smaller}
.note::before {
    content: counter(note);
    position: @;
    vertical-align: super;
    font-size: larger}

results in a rendering similar to this:

Same text, with the SPAN replaced by “(1)” and its content moved to the end.

Rendering of a text with footnotes.

This example shows the use of chained regions: text from region 1 continues in region 2, 3 and 4. And it shows how to use pseudo-elements to style text in a particular region: text in region 1 is bigger than in other regions.

Image of a complex, 3-column layout

Example rendering

We assume a document fragment similar to this:

<div id=article>
  <p><img src="sunset" alt="">
  <p>This is an example…
  <h1>More Details</h1>
  <p>This illustrates…
  <p>Then, the example…
  <p>Finally, this…

The style sheet makes the DIV into a template element with five regions, called A, 1, 2, 3 and 4. The regions are grouped into two chains: region A on its own, and the chain consisting of 1, 2, 3 and 4.

#article {
  display: "A A 4"
           "A A 4"
           "1 1 4"
           "2 3 4";
  chains: 1 2 3 4 }

All children go into region 1 (and continue in 2, 3 and 4 as needed). The IMG element goes into region A. We assume for simplicity that there is only one IMG element:

#article > * { position: 1 }
#article img { position: A }

The text in region 1 is bolder, larger and a different color than in the other regions. Also, an H1 that falls into this region is rendered differently from other H1s:

::slot(@) {
  font-weight: bold;
  color: #0C3D5F;
  font-size: larger }
h1::slot(@) {
  color: crimson;
  display: run-in }

(For brevity, the example doesn't show the style rules to set the color and background, to make the text justified, add the left border to the second H1, etc.)

3. Features out of scope

A number of features that are related to grid layouts are not handled in this module. Some of them are in other modules.

3.1. Repeating templates

The templates defined by this specification have a fixed number of slots, independent of the amount of content or the number of child elements. In some situations it may be useful to define a template and then, in the case there is more content than fits, automatically create new copies of the template, to the side of or below the first one, just like new pages are created in paged media or new columns in multi-column layouts.

In some cases it may be possible to simulate that behavior by putting the template element inside a column layout.

3.2. Non-rectangular shapes and wrap-arounds

This specification allows to chain multiple slots together to form complex shapes, but each of the slots is itself still rectangular.

Another module, CSS exclusions and shapes [CSS3-EXCLUSIONS], is expected to allow floating elements to have non-rectangular shapes and allow positioned elements to cause wrap-around.

4. Declaring templates: the ‘display’ property

ISSUE-123: One way to experiment safely with implementations before the specification reaches Candidate Recommendation status is to add an identifier with a vendor prefix somewhere in the value, e.g., ‘display: -my-product "aa" "bc"’ or ‘display: -my-product("aa" "bc")’.

Name: display
New value: <display-type>? && [ [ <string> [ / <row-height> ]? ]+ ] <col-width>*
Percentages: N/A
Computed value: specified value

A value of this form is called a template.

An element with such a ‘display’ value is similar to a table element, in that its content is laid out in rows and columns. The two main differences are that the number of rows and columns doesn't depend on the content, but is fixed by the value of the property; and that the order of the descendants in the source document may be different from the order in which they appear in the rendered template.

The <display-type> is one of the following keywords. An omitted keyword is equivalent to ‘block’.

<display-type> = inline |
block | list-item | inline-block | table | inline-table |
table-row-group | table-header-group | table-footer-group | table-row
| table-column-group | table-column | table-cell | table-caption |
These three values are equivalent. The element is an inline-level element.
The element is formatted as a list item. If the element has the value ‘inside’ for its ‘list-style-position’, that ‘inside’ is treated as if it were ‘outside’.
These two values are equivalent.
This creates a principal block-level box that is the template, with around it an anonymous ‘table-row’ box and around it a box of the indicated type. Around it may be more anonymous boxes according to the rules for Anonymous table objects [CSS21].
This creates a principal block-level box that is the template and around it a ‘table-row’ box. Around it may be zero or more anonymous boxes according to the rules for Anonymous table objects [CSS21].
The template is ignored and the element is treated as an element of the indicated type.
The element is a table cell with a template.
The element is a table caption with a template.
The template is ignored and the element is treated as for ‘display: none’.

Future display types added in other modules?

Note that ‘display’ is extended to apply to ‘@page’ rules as well and that it has a different default there, viz., ‘"@"’. See “Templates in paged media” below.

Each string consist of one or more at signs (“@”), letters (or digits, see <letter> below), periods (“.”) and spaces. Each string represents one row in the template, each character other than a space represents one column in that row. Spaces have no meaning. They may be added for readability.

The symbols in the template have the following meaning

a letter
slot for content.
(at sign) default slot for content.
(period) white-space.

Multiple identical letters in adjacent rows or columns form a single slot that spans those rows and columns. Ditto for multiple “@”s. Uppercase and lowercase are considered to be the same letter (i.e., the template is case-insensitive).

Non-rectangular slots and multiple slots with the same letter are illegal. A template without any letter or “@” is illegal. A template with more than one “@” slot is illegal. These errors cause the declaration to be ignored.

Note: non-rectangular and disconnected regions may be permitted in a future update of CSS.

Rows with fewer columns than other rows are implicitly padded with periods (“.”) (that will thus not contain any elements).

Each slot (letter or “@”) acts as a block element for its contents.

Each <row-height> sets the height of the preceding row. The default is ‘auto’. The values can be as follows:

An explicit height for that row. Negative values make the template illegal. If the length is expressed in ‘gr’ units, these refer to the inherited grid, not the grid defined by the template itself (see “Definition of the ‘gr’ unit in a template element”).
The row's height is determined by its contents. See the algorithm below.
(asterisk) All rows with an asterisk will be of equal height. See the algorithm below.

Each <col-width> sets the width of a column. If there are more <col-width>s then columns, the last ones are ignored. If there are fewer, the missing ones are assumed to be ‘*’. Each <col-width> can be one of the following:

An explicit width for that column. Negative values make the template illegal.
(asterisk.) All columns with a ‘*’ have the same width. See the algorithm below.
The column's width is determined by its contents. See the algorithm below.
The column's width is constrained to be greater than or equal to p and less than or equal to q. p and q stand for [ <length> | max-content | min-content | * ]. There may be white space around the p and q. If q < p, then q is ignored and ‘minmax(p,q)’ is treated as ‘minmax(p,p)’.
Equivalent to ‘minmax(min-content, max-content)’.

Note that it is legal to specify no widths at all. In that case, all columns have the same width.

ISSUE-127: It has been suggested that the template may become too verbose in the case of column widths that are very small factions, e.g., a column of 1/40th of the width:

display: "abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

Abbreviating this with percentages (‘2.5% 97.5%’) introduces an opportunity for errors (e.g., ‘3% 98%’ causes the template to be rejected). Abbreviating with numbers,

display: "ab"  * 39*

(or even just ‘1 39’) is safer. On the other hand, those 39 identical letters make it immediately clear what the intention is…

The orientation of the template is independent of the writing mode (‘direction’ and ‘block-flow’ properties): the first string is the topmost row and the first symbol in each string is the leftmost column.

<style type="text/css">
  div { display: ".aa..bb." }
  p.left { position: a }
  p.right { position: b }
  <p class=left>Left column
  <p class=right>Right column

An element with a template value for its ‘display’ property is called a template element. An element's template ancestor is defined (recursively) as follows:

5. Computing the width of the slots

First, the intrinsic minimum and intrinsic preferred widths are defined as follows:

Next, the layout algorithm distinguishes between elements with and without an a-priori known content width.

The width isn't known a-priori, if, e.g., ‘width’ is ‘auto’ and the element is floating, absolutely positioned, inline-block or a child of a block with vertical writing mode.

An extra step may be necessary in paged media if a page break occurs inside a template (only in the case of an element-based template, see below). If the template, after computing the width and height, is too big to fit on the current page, and if a suitable break point exists, the part of the template after that break point is put on the next page. The width of the containing block on that page may be different if that page has different margins from the current page (see [CSS3PAGE]) and thus the width and height of that part of the template must be recalculated in the new context.

Note that the widths of the columns can be completely determined before laying out any of the contents as long as there are no columns with a <col-width> of ‘min-content’ or ‘max-content’.

Do we define restrictions or approximations for slots that are part of a chain to avoid complicated optimization algorithms?

6. Computing the height of the slots

The height of the template is the smallest possible under the following constraints:

  1. Rows with a height set to <length> have that height.
  2. No row has a negative height.
  3. All rows with a height set to ‘*’ are the same height.
  4. Every sequence of one or more rows of which at least one has a height set to ‘auto’ is at least as high as every letter or “@” slot that spans exactly that sequence of rows.
  5. If the computed value of the element's ‘height’ is ‘auto’, then every sequence of one or more rows of which at least one has a height set to ‘*’ is at least as high as every letter or “@” slot that spans exactly that sequence of rows.
  6. The whole template is at least as high as the computed value of the element's ‘height’, unless that value is ‘auto’, or unless all rows have a height set to <length>.

If the template is higher than the element's ‘height’, the element overflows, see ‘overflow’.

This may have multiple solutions in case the element has a fixed height that is larger than the sum of the minimum sizes of each row. Do all rows without a fixed <length> become taller by the same amount? or by the same percentage? or do rows with ‘auto’ only increase if there are no rows with ‘*’? Something like a box-flex-group property (and optionally a box-flex as well (see [CSS3-FLEXBOX]) can give the designer explicit control. The note below hints at that. Another option is to have ‘fill’ and ‘filll’ units as in TEX: calc(5em + 2fill).

Note: In a future update of CSS, rows might get a property to specify how the height of that row is adjusted in case the above calculation yields a template that is less tall than the element itself.

The height of a slot is measured as if the slot had one anonymous block as a child that contains all the slot's contents, and both the slot and the anonymous block have a ‘block-flow’ of ‘tb’ and the anonymous block's height is computed as a flow root (see “Auto heights for flow roots” in [CSS3BOX]). Roughly, this means the height is from the top margin edge of the topmost element to the bottom margin edge of the bottommost element or of the bottommost float.

The intrinsic height of a ‘.’ slot is 0.

This example divides the window in three rows and three columns, separated by 1em of white space. The middle row and the middle column are flexible, the others are fixed at a specific size. The first column is 5em wide, the last one 10em.

<style type="text/css">
  body {
    height: 100%;
    display: "a   .   b   .   c"  /2em
             ".   .   .   .   ."  /1em
             "d   .   e   .   f"
             ".   .   .   .   ."  /1em
             "g   .   h   .   i"  /2em
             5em 1em  *  1em 10em}
  #logo {position: a}
  #motto {position: b}
  #date {position: c}
  #main {position: e}
  #adv {position: f}
  #copy {position: g}
  #about {position: h}
<p id=logo><img src=...
<p id=motto>Making Web pages since 1862
<p id=date>August 2, 2004

[Add example with three columns, first two as narrow as possible, third one taking up all remaining space.]

7. Flowing content into the template: the ‘position’ property

One way to experiment safely with implementations before the specification reaches Candidate Recommendation status is to add an identifier with a vendor prefix somewhere in the value, e.g., ‘position: a -my-product’ or ‘position: -my-product(a)’.

Name: position
New value: <letter> | same
Percentages: N/A
Computed value: <letter>’ or ‘static’; see text

This value of the ‘position’ property specifies into which row and column of a template the element is placed. The <letter> must be a single letter or digit, with category Lu, Ll, Lt or Nd in Unicode [UNICODE]), or a “@” symbol.

The element is taken out of the flow of its parent and put into the specified slot in its template ancestor. [If the slot is the first of a chain, see ‘chains’, the element is put in that chain, not necessarily in the first slot.] If there is no slot of this name, the computed value is ‘static’. [If the slot is part of a chain, but not the first slot in the chain, the computed value is likewise ‘static’.]
A value of ‘same’ computes to the same letter as the most recent element with a letter as computed value that has the same template ancestor. If there is no such element, the value computes to ‘static’.

The containing block of an element with one of these values for ‘position’ is the slot in the template into which it is flowed.

Multiple elements may be put into the same slot. They will be laid-out according to their ‘display’ property in the order they occur in the source document.

The content of a template element is put in the slot marked with “@”s. If there is no such slot, the content is put in the first (leftmost) slot on the first row that doesn't consist of only “.”. [If the slot is part of a chain,, the content is put in that chain instead.]

A common markup in HTML for illustrations with captions is as follows:

<div class=figure>
 <p><img src="paul.jpg" alt="...">
 <p class=caption>A pond in a playground in Amsterdam

The caption can be put above the image by using a template as follows:

div.figure {display: "aaa"
                     * min-content *}
div.figure p {position: b}
div.figure p.caption {position: a; text-align: center}

The caption can be wider than the image and the image will be centered.

When the figure is floating, it is probably better to not let the caption become wider than the image (unless the caption cannot be made narrow enough):

div.figure {float: right; display: "a" "b" min-content}
div.figure p {position: b}
div.figure p.caption {position: a; text-align: center}

In this example, a form is laid out on a grid, with two labels and two input boxes and a submit and a reset button:

form {
  border: thin solid;
  display: "aaaa.bbbb"
           "...ee..ff" }
label[for=minv] { position: a }
input#minv { position: b; display: block }
label[for=maxv] { position: c }
input#maxv { position: d; display: block }
input[type=submit] { position: e; display: block }
input[type=reset] { position: f; display: block }

Here is the fragment of HTML that the style is applied to:

<form action="./">
  <label for=minv>Enter minimum value:</label>
  <input id=minv name=minv>
  <label for=maxv>Enter maximum value:</label>
  <input id=maxv name=maxv>
  <input type=submit value="OK">
  <input type=reset value="Reset">

The addition of ‘display: block’ causes the form controls to use the width computation of blocks, in other words: they will be as wide as their containing block, which in this case means that they will be as wide as the slot they are assigned to. Without it, they would be inline elements and just be left-aligned in their slots.

Image simulating the layout of the example

Possible rendering of the example.

This example shows that templates can be nested. The body has two columns. The #content element that goes into the second column has itself another template, into which the various “modules” are placed.

[Screendump with nested templates]

Possible rendering of the nested templates. (The borders are added for clarity, they don't occur in the style rules below. The red border is the inner template.)

For clarity, the inner template uses different letters for the slots than the outer template. This is not required.

<style type="text/css">
body {
     display: "a   b"
              10em *;
#nav {
     position: a;
#content {
     position: b;
     display: "c   .   d   .   e   "
              ".   .   .   .   .   "/1em
              ".   .   f   .   .   "
               *  1em  *  1em  *;
.module.news {
     position: c;
.module.sports {
     position: d;
.module.personal {
     position: e;
#foot {
     position: f;
<ul id="nav">
<div id="content">
    <div class="module news">
         <p>There will be weather</p>
    <div class="module sports">
         <p>People like football.</p>
    <div class="module sports">
         <p>There was a brawl at the chess tournament</p>
    <div class="module personal">
         <h3>Your Horoscope</h3>
         <p>You're going to die (eventually).</p>
    <p id="foot">Copyright some folks</p>


This example shows the use of ‘same’ to put DD elements in the same slot as the preceding DT.

DL {display: "a.b.c"  * 2em * 2em *}
DT.mineral {position: a}
DT.animal {position: b}
DT.plant {position: c}
DD {position: same; margin-left: 1em}
 <DT class=animal>falcon
 <DD>This bird of prey...
 <DT class=animal>rabbit
 <DD>Local restaurants...
 <DT class=mineral>granite
 <DD>This rock occurs...
 <DT class=plant>olive
 <DD>The fruit of...
 <DT class=mineral>limestone
 <DD>A rock composed of...
 <DT class=plant>pine
 <DD>The western half...


Possible rendering of the DL list, with items sorted into three columns.

Another, more verbose syntax could be more readable for infrequent users: ‘position: slot(a)’. (But maybe harder to remember when writing style rules?)

8. The ‘::slot()’ pseudo-element

The slots of a template element can be individually addressed with the slot()’ pseudo-element.

For example, the following sets the color and vertical alignment of some of the slots in a template:

body { display: "aaa"
                "bcd" }
body::slot(b) { background: #FF0 }
body::slot(c), body::slot(d) { vertical-align: bottom }

The selector ‘E::slot(X)’ selects the part of an element E that falls inside the slot with name X of a template T, where T is either the template of E itself (if E is a template element) or the template of the template ancestor of E. If there is no such template T, or if it does not contain a slot called X, the selector matches nothing.

The following example shows the difference between using the ‘::slot()’ pseudo-element in combination with a template element and in combination with a descendant of such an element.

body { display: "a b c" }          /* Make BODY a template element */
body::slot(a) { background: #FF0 } /* Color whole slot */
p::slot(a) { background: #FC0 }    /* Color intersection of P and slot a */

Expand example with a screen shot.

Only the following properties apply to the ‘slot()’ pseudo-element. Those marked with a * apply only to the ‘slot()’ pseudo-element of a template element.

For example, if P is a child of DIV, then the 2nd rule below specifies the alignment of content in slot a, but the 3rd rule has no effect:

DIV { display: "a b b" }                 /* Rule 1 */
DIV::slot(a) { vertical-align: bottom }  /* Rule 2 */
P::slot(a) { vertical-align: bottom }    /* Rule 3 */

What is the text indent of a P that starts in slot a? 10pt or 20pt?

P { font-size: 10pt; text-indent: 1em }
P::slot(a) { font-size: 20pt }

The background of a slot is drawn immediately on top of the background of the element itself. E.g., the background set on ‘P::slot(a)’ is immediately in front of the background set on ‘P’.

Need to define exactly how properties apply, similarly to :first-line: fictional tag sequence, ambiguous cases…

Need to define the width when a slot has padding and border, including when the width is too small.

Note that slots can have borders and padding, but no margins (cf. table cells).

9. Vertical alignment

The ‘vertical-align’ property of a ‘::slot()’ pseudo-element can be used to align elements vertically in a slot. The effect is as if the hypothetical anonymous block that contains the slot's contents is positioned as follows:

The content of the slot is aligned to the bottom of the slot: the bottom margin edge of the anonymous block coincides with the bottom of the slot.
The content of the slot is vertically centered in the slot: the distance between the top margin edge of the anonymous block and the top of the slot is equal to the distance between the bottom margin edge of the anonymous block and the bottom of the slot. (Note that if the content overflows the slot, it will overflow both at the top and at the bottom.)
The anonymous block that encloses the content is placed as high as possible under two constraints:
  1. The top margin edge of the anonymous block may not be higher than the top edge of the slot.
  2. The topmost baseline in the content may not be higher than the topmost baseline of content in any other slot in the same row that also has ‘vertical-align: baseline’. Baselines of content inside floats are not taken into account. Slots that span several rows are considered to occur in their topmost row.

For all other values, the content is top aligned: the top margin edge of the anonymous box coincides with the top edge of the slot.

10. Page-based templates and other templates in paged media

A template can also be attached to a page, rather than an element. Such a template is called a page-based template as opposed to an element-based template.

The difference between page-based layout templates and element-based ones is that the size of a slot in a page-based layout template only depends on the template and the page size, never on the intrinsic size of the content.

Another difference is that content that overflows a slot may cause a page break: the rest of the content is put on another page. See below.

The syntax of a page-based template is the same as that of an element-based one, but the declaration appears in an ‘@page’ rule and any <col-width> or <row-height> that is neither ‘*’ nor a <length> is treated as if it were ‘*’.

Also, a <display-type> may be present, but has no effect.

Although the occurrence of keywords, such as ‘fit-content’ or ‘auto’, is valid and well defined, a UA, especially an editor, may want to issue a warning, because those keywords don't have any useful function in page-based templates.

@page :first { display: "abc" "def" }
@page { display: "def" }

body {position: e}
h1 {position: b}

The default ‘display’ value of a page is ‘display: "@"’.

The following rule is typically not needed, because it is the default:

@page { display: "@" }

The height of the slots in a template is computed as in the section “Computing the height of the slots,” except that the page area's height [CSS3PAGE] is used instead of the element's height. Similarly, the width of the slots is computed as in the section “Computing the width of the slots,” but with the page area's width replacing the element's width.

Note that certain rules in those sections are never applied, because the page area's width and height are always known a-priori and the width and height of slots is always a <length> or ‘*’.

If a slot of a page-based template on non-interactive media has an ‘overflow’ property of ‘visible’, then content that overflows that slot in the block progression direction (i.e., below the slot in the case of horizontal text) causes a page break and is continued on the next page. [What happens in non-interactive media with an ‘overflow’ of ‘scroll’ or ‘auto’?]

For page breaking purposes, each slot is considered as a page and the page break properties on the elements in that slot determine where the content for that slot is broken. Content after the page break is put in the slot of the same name on the next page that has such a slot. If there is no such page the content after the page break is not displayed? displayed in the default slot?

Note that this may happen if the template for the first page (‘@page :first’) uses a letter that occurs in no other @page rule. Possibly also if a page template is bound to a “named page” [CSS3GCPM] and that named page is not allowed to repeat. (At the time of writing, this is only a proposal in the GCPM Module.)

Note that an element A that appears later in the document than an element B may thus be displayed on an earlier page than element B, because their respective slots are broken across pages in different ways.

Because of limitations of a device (e.g., limited memory), it may be that a UA has to print a page (force page breaks) even though some slots aren't filled yet.

This example shows how the first page may have a different layout from the other pages. The slot ‘a’ only occurs on the first page. If the content for that slot (in this case: all H1 elements) is too long, the remaining content of that slot will not be displayed. The slot ‘@’ occurs on normal pages and all its content can thus be displayed by adding additional pages.

@page :first { display: "a" "@" }
@page { display: "@" /* This is the default */ }
h1 {position: a}

Note that “page masters” (sequences of different templates for sequences of pages) can be made with the selectors defined in [not yet decided].

Element-based templates in paged media may be broken across pages, subject to the page break properties. In addition to the break points listed in the Paged Media module [CSS3PAGE], a page break may occur between two rows in a template, if there is a possible break point at the same height or higher in all slots that span those two rows; and a page break may occur inside a row if there is a possible break point in all slots in that row.

Try to be more precise?

If ‘page-break-before’ or ‘page-break-after’ is ‘right’, ‘left’ or ‘always’ on an element inside a slot in an element-based template, the value is treated as ‘auto’ instead.

The ‘page’ property does not apply to elements inside a slot of an element-based template.

Any other forced page break (see section 5.5 of Paged Media [CSS3PAGE]) causes a new page to be created and all content in the document after this page break will be put in slots on the new page or on later pages: slots on any previous pages will not be further filled.

A slide presentation can be made with a template for each page (i.e., slide) and forced page break between the slides:

@page	{ display: "a" / 5em
	           "@" / *
	           "b" / auto }
h1	{ page-break-before: always;
	  position: a }
p.note	{ position: b }

With a document similar to this: (fragment)

<h1>Slide 1 title</h1>
 <li>Topic one
<h1>Slide 2 title</h1>
 <li>More topics
<p class=note>Note the note

The document in the example above doesn't have an element that corresponds to a slide; a slide simply starts at an H1 and ends before the next H1. But if there is a DIV around each slide (as is the case in many slide formats in practice), the same effect can also be achieved without page-based templates, by using the ‘vh’ unit [CSS3VAL]:

div.slide {height: 100vh; display: "a"/5em "@" "b"/intrinsic;
    page-break-before: always}
h1 {position: a}
p.note {position: b}

With a document similar to this: (fragment)

<div class=slide>
 <h1>Slide 1 title</h1>
  <li>Topic one
<div class=slide>
 <h1>Slide 2 title</h1>
  <li>More topics
 <p class=note>Note the note

Both page-based and element-based templates can be used in the same document.

@page { display: "a@" }
:lang(fr} {position: a}
div.special {display: "abc" "abd"}

Here is a page as one might find in a newspaper. It combines a layout template with multicolumn layout.

5-column newspaper page with some   blocks of text that span several columns

The front page of a newspaper, with the first parts of several stories that are continued on other pages and headings and images that span several columns.

@page :first {
  display: "A  A  A  A  A  A  A  A  A" / 5cm
           ".  .  .  .  .  .  .  .  ." / 0.25cm
           "B  .  C  C  C  C  C  C  C" / *
           "B  .  C  C  C  C  C  C  C" / *
           "B  .  C  C  C  C  C  C  C" / *
           "B  .  C  C  C  C  C  C  C" / *
           "B  .  C  C  C  C  C  C  C" / *
           "B  .  D  D  D  D  D  D  D" / *
           "B  .  D  D  D  D  D  D  D" / *
           "B  .  E  E  E  .  F  F  F" / *
           "B  .  E  E  E  .  F  F  F" / *
           "B  .  E  E  E  .  F  F  F" / *
            * 3em * 3em * 3em * 3em *
h1 {position: a; border-bottom: thick; margin-bottom: 1.5em}
#toc {position: b; margin-right: -1.5em; border-right: thin;
  padding-right: 1.5em}
#leader {position: c; columns: 4; column-gap: 3em}
#art1 {position: d; columns: 4; column-gap: 3em; border-top: thin}
#art2 {position: e; columns: 2; column-gap: 3em}
#art3 {position: f; columns: 2; column-gap: 3em}

If a slot on a page is full and the content continues on the next page, it may be useful to insert something like “continued on page X.” This is useful at any page break, but more important if there are multiple “flows” of content on each page. Maybe a page-break-content property? ‘page-break-content: "▶ continued on p. " targetcounter(???, page)’ or extend text-overflow from [CSS3TEXT]?

How do you set the ‘vertical-align’ property of a slot in a page? Does the ‘::slot()’ pseudo-element apply? ‘@page :first :slot(A) {vertical-align: bottom}

11. Stacking order

An element with a computed value of a letter for its ‘position’ is a positioned element (see [CSS3POS]) and thus the ‘z-index’ property applies to it. The general rules for stacking contexts [ref in CSS3?] apply.

Note that an element can only have such a computed value if it has an ancestor that is a template element.

This example uses ‘z-index’ and negative margins to make the element in the middle slot partly overlap the other slots:

body { display: "a.b"
       height: 240px;
       width: 240px }
::slot(a) { background: #0C0 }
::slot(b) { background: #C00 }
::slot(d) { background: #00C }
::slot(e) { background: #A0A }
#c { background: #FD0; height: 120px; position: c;
     margin: -20px; z-index: 1 }

Five colored rectangles

Rendering of the above example.

12. Floating elements inside templates

An element may be positioned inside a template (computed value of <letter> for its ‘position’ property) and be a floating element at the same time (computed value of its ‘float’ property is other than ‘none’). The following cases must be distinguished:

13. Definition of the ‘fr’ unit in a template element

The Grid Layout Module [CSS3-GRID-LAYOUT] defines a ‘fr’ unit (for “fraction”) that is usable with certain properties that position or size boxes. A template element defines an implicit grid (in the terminology of that module) for use with the ‘fr’ unit. The vertical grid lines are formed by the left and right content edges of the template element and by the edges between the columns of the template. The horizontal grid lines are formed by the top and bottom content edges of the template element and by the edges between the rows of the template. The top content edge and the left content edge have the number 0.

In other words, a template with n columns and m rows defines n + 1 vertical grid lines numbered 0 to n and m + 1 horizontal grid lines numbered 0 to m.

For example, with the following style sheet

div {
  display: "abc"
  position: relative}
p {
  position: f}
#p1 {
  position: absolute;
  top: 1fr;
  left: 2fr}

and this document fragment

 <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed
 do eiusmod tempor incididunt ut labore et dolore magna aliqua.
 <p id=p1>Position me.

the “p1” element will be positioned with its top left corner against the top left corner of slot f. But note that it is not part of the content of slot f, it overlaps with it.

14. Chaining slots: the ‘chains’ property

Slots must be rectangular, but the appearance of non-rectangular slots can be achieved to a large extent by chaining slots together. Content that is positioned in the first slot of a chain is automatically continued in the second slot if the first slot is full, and then the third, etc.

Name: chains
Value: none | <letter>+ [ , <letter>+ ]*
Initial: none
Applies to: template elements
Inherited: no
Percentages: N/A
Media: visual
Computed value: specified value

A value of ‘none’ means the element's template has no chains. Otherwise the value consists of one or more comma-separated lists of letters. No letter may appear more than once in the value. Letters that do not occur in the template are ignored, but do not make the value invalid. A list with only ignored letters is itself ignored.

All the non-ignored letters in a list, except for the last one, must refer to slots whose size does not depend on their contents, otherwise the list is ignored. The size of a slot does not depend on its content if all the columns and all the rows that the slot spans have a width, respectively height, that is a <length> or ‘*’.

Each non-ignored list defines one chain.

Each chain is filled with content in an analogous way to the pages in paged media: all the content that is positioned to the first slot in the chain is flowed, in document order, into the first slot in the chain until the slot is full, the rest is flowed into the second slot until it is full, etc.

Content must only be split between slots at an allowed page break [CSS3PAGE]. As for page breaks, if a break occurs in the margin between blocks, all adjoining margins are set to zero.

CSS3 does not define what is the best break point to split content over slots. However, it is recommended to use the last possible break point that does not cause overflow. (If such a break point exists.)

Note: It is the author's responsibility to make the height of relevant slots an integral number of lines if he wants to ensure that the lines in chained slots are aligned. The height does not automatically “snap” to a multiple of the line height.

The following template creates a double-staircase layout. In case the content is too long for the staircase, a slot of flexible height is added at the bottom.

div { display: "@@..ff...." / 3.6em
               ".aa..gg..." / 3.6em
               "..bb..hh.." / 3.6em
               "...cc..ii." / 3.6em
               "....dd..jj" / 3.6em
               ".........." / 0.6em
               "eeee..kkkk" / auto;
   chains: @ a b c d e, f g h i j k}
#first { position: @ }
#second { position: f }

This could be applied to a document fragment such as

  <P ID=first>...
  <P ID=second>...

Here is a paragraph shaped as a circle:

p { width: 12em;
    display: ". . . . @ @ . . . ." / 1.2em
             ". . a a a a a a . ." / 1.2em
             ". b b b b b b b b ." / 1.2em
             ". b b b b b b b b ." / 1.2em
             "c c c c c c c c c c" / 1.2em
             "c c c c c c c c c c" / 1.2em
             ". d d d d d d d d ." / 1.2em
             ". d d d d d d d d ." / 1.2em
             ". . e e e e e e . ." / 1.2em
             ". . . . f f . . . ." / 1.2em
             "g g g g g g g g g g" / auto;
   chains: @ a b c d e f g }

Here is a page-based template that creates a two-column layout with a “hole” in the center:

@page:first {
    chains: a b c d e f }
@page::slot(g) {
    vertical-align: middle }

body { position: a }
h1 { position: g }

Note: For more anaylysis of the possibilities and limits of non-rectangular slots, see the PhD thesis of César Acebal [ACEBAL2010].

Chaining of rectangular slots is not enough to create layouts with holes, e.g., an image in the middle of a text. Allowing non-rectangular, connected regions (in addition to chaining) would allow an example such as this:

display: "A A A . . ."
         "A . A . . ."
         "A A A . . ."
         ". . . B B B"
         ". . . B . B"
         ". . . B B B";
chains: a b;

Such cutouts in the middle of text usually create text that is difficult to read, and that is why there is no ‘float: center’, e.g.

Note that a slot can have overflowing content even if it is part of a chain: it can have content that is too wide and content that is too tall but cannot be broken.

15. Breaking content between slots in a chain

The ‘break-before’, ‘break-after’ and ‘break-inside’ properties have values that control breaking of content between slots in a chain (in addition to the values that control breaks between pages and columns, defined in [CSS3PAGE] and [CSS3COL]):

Name: break-inside
New value: avoid-slot
Percentages: N/A
Computed value: specified value
Name: break-before’, ‘break-after
New value: slot | avoid-slot
Percentages: N/A
Computed value: specified value

The new values are:

Avoid a break inside (before, after) the generated box.
Always force a break before (after) the generated box.

16. CR exit criteria

For this specification to be advanced to Proposed Recommendation, there must be at least two independent, interoperable implementations of each feature. Each feature may be implemented by a different set of products, there is no requirement that all features be implemented by a single product. For the purposes of this criterion, we define the following terms:

each implementation must be developed by a different party and cannot share, reuse, or derive from code used by another qualifying implementation. Sections of code that have no bearing on the implementation of this specification are exempt from this requirement.
passing the respective test case(s) in the official CSS test suite, or, if the implementation is not a Web browser, an equivalent test. Every relevant test in the test suite should have an equivalent test created if such a user agent (UA) is to be used to claim interoperability. In addition if such a UA is to be used to claim interoperability, then there must one or more additional UAs which can also pass those equivalent tests in the same way for the purpose of interoperability. The equivalent tests must be made publicly available for the purposes of peer review.
a user agent which:
  1. implements the specification.
  2. is available to the general public. The implementation may be a shipping product or other publicly available version (i.e., beta version, preview release, or “nightly build”). Non-shipping product releases must have implemented the feature(s) for a period of at least one month in order to demonstrate stability.
  3. is not experimental (i.e., a version specifically designed to pass the test suite and is not intended for normal usage going forward).

The specification will remain Candidate Recommendation for at least six months.

A test suite will be developed during the Candidate Recommendation phase of this specification.

17. History

(This section is not normative.)

The following types of use cases were considered for template-based layout.

  1. Standard Web pages.

  2. Grids and other table-like layouts. This includes grid layouts, frame layouts and table-like subdivision of a rectangular area.

  3. A layout structure with “flex”ing information. The flexing is represented by constraints that specify how the cells are to relate to one another: which cells are to be allowed to grow or shrink and how much. There may also be a priority ordering, which determines, based on the size of the allowed display window, which cells shrink, which grow and under which conditions.

  4. Layout structures with absolutely positioned (fixed-size) elements; for example a block of text into which several illustrations intrude at fixed positions within the block. This is like a float with respect to tightly wrapping the text around the intrusion, but the position of the intrusion is determined by the layout structure, not the content flowed into that structure.

    An example of this is a multicolumn layout with one or more “absolutely positioned floats” that intrude on the columns (see figure).

    An image that partially overlaps two   columns makes the text wrap around it on both sides.

    An image (or a “pull quote”) is placed centered on the page and intrudes on two areas.

  5. Multiple, disconnected, fixed-size areas on a page that are chained together, each one receiving the content that doesn't fit in the previous slot. In combination with page breaks, this may give a layout as often seen in newspapers: the first few lines of each story on the first page, the rest of the story in other areas on subsequent pages. (It will probably need a way to conditionally insert “continued on page 7” or similar text.)

For comparing proposals for template-based layouts, the working group identified four important aspects of each proposal:

  1. the physical layout structures – the way of structuring the “cells” (slots) into which content is flowed. This includes a way to identify the various layout containers.

  2. the binding mechanism – the way to specify that a given element (and its descendants) are to be placed in a given layout cell.

  3. the property distribution mechanism – the way to put properties onto the layout structure and the cells within it.

  4. the flexing mechanism – the way to describe how the layout structure should adapt itself to the higher level container (window) in which it is placed. This includes statements about which cells should grow and when they should grow.

In this specification, these aspects are as follows:

  1. A character matrix is used to show the layout structure and the cells are named by the character used to show where they are positioned.

  2. The binding of content to cells is handled by the ‘position’ property which identifies a cell to which the content is bound.

  3. The shape, size and flexibility of the layout are specified with the character matrix. Some properties (background, border and vertical alignment) are attached to individual slots.

  4. There is limited “flexing” information. The choice is between fixed size, a fraction of the available size or the content's intrinsic size. (The latter is further subject to min/max sizes specified on that content.) It is not possible to say, e.g., that some column can only become wider if all other columns are at their maximum size.

18. Changes

Summary of changes since 29 April 2010 draft:


The first ideas for describing a template in CSS date from 1996 and are described in Frame-based layout via Style Sheets by Bert Bos, Dave Raggett and Håkon Wium Lie. The idea was revived in 2005 on the request of W3C's Device Independence Working Group and benefited especially from discussions with Rhys Lewis and Rotan Hanrahan from that group.

This specification was further influenced by ideas about form layout by Dave Raggett [member-only link] and an early write-up of the features of XUL by Ian Hickson [member-only link].

Andy Clarke, Jina Bolton and Kevin Lawver provided use cases, examples and requirements. The analysis in the History section is a slightly shortened version of work by Steve Zilles.

César Acebal built the first prototype. Andrew Fedoniouk built the second. A third prototype was made by Alexis Deveria.


Normative references:

Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. W3C Recommendation. URL: http://www.w3.org/TR/2011/REC-CSS2-20110607
Bert Bos; Elika J. Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 15 February 2011. W3C Candidate Recommendation. (Work in progress.) URL: http://www.w3.org/TR/2011/CR-css3-background-20110215
Bert Bos. CSS basic box model. 9 August 2007. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2007/WD-css3-box-20070809
Håkon Wium Lie. CSS Multi-column Layout Module. 12 April 2011. W3C Candidate Recommendation. (Work in progress.) URL: http://www.w3.org/TR/2011/CR-css3-multicol-20110412
Håkon Wium Lie; Melinda Grant. CSS3 Module: Paged Media. 10 October 2006. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2006/WD-css3-page-20061010
Bert Bos. CSS3 Positioning Module. (forthcoming). W3C Working Draft. (Work in progress.)
L. David Baron. CSS3 module: Syntax. 13 August 2003. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2003/WD-css3-syntax-20030813
Bert Bos; David Hyatt. CSS3 Tables Module. (forthcoming). W3C Working Draft. (Work in progress.)
Elika J. Etemad; Koji Ishii; Shinyu Murakami. CSS Text Level 3. 1 September 2011. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2011/WD-css3-text-20110901/
Elika J. Etemad; Koji Ishii; Shinyu Murakami. CSS Writing Modes Module. (forthcoming). W3C Working Draft. (Work in progress.)
Håkon Wium Lie; Tab Atkins; Elika J. Etemad. CSS Values and Units Module Level 3. 6 September 2011. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2011/WD-css3-values-20110906/
The Unicode Consortium. The Unicode Standard. 2003. Defined by: The Unicode Standard, Version 4.0 (Boston, MA, Addison-Wesley, ISBN 0-321-18578-1), as updated from time to time by the publication of new versions URL: http://www.unicode.org/standard/versions/enumeratedversions.html

Other references:

César Fernández Acebal. ALMcss: Separación de estructura y presentación en la web mediante posicionamiento avanzado en CSS. 2010. Oviedo, Spain. PhD thesis URL: http://di002.edv.uniovi.es/~acebal/phd/dissertation.pdf
Vincent Hardy. CSS Exclusions Module. Proposal for a CSS module. (Retrieved 15 November 2011) URL: http://dev.w3.org/csswg/css3-exclusions/
Tab Atkins Jr.; Alex Mogilevsky; L. David Baron. Flexible Box Layout Module. 22 March 2011. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2011/WD-css3-flexbox-20110322/
Alex Mogilevsky; et al. Grid Layout. 7 April 2011. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2011/WD-css3-grid-layout-20110407
Håkon Wium Lie. CSS Generated Content for Paged Media Module. 8 June 2010. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2010/WD-css3-gcpm-20100608
Håkon Wium Lie; et al. Media Queries. 27 July 2010. W3C Candidate Recommendation. (Work in progress.) URL: http://www.w3.org/TR/2010/CR-css3-mediaqueries-20100727/
Tantek Çelik; et al. Selectors Level 3. 29 September 2011. W3C Recommendation. URL: http://www.w3.org/TR/2011/REC-css3-selectors-20110929/