Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
CSS is a simple, declarative language for creating style sheets that specify the rendering of HTML and other structured documents. This module defines a typographic grid for CSS. It has features to set up a grid template, to flow content into it, and to absolutely position elements on a grid.
The ‘grid
’
property sets up a matrix of rows and columns and designates empty areas
and areas for content (called “slots”). The ‘flow
’ property
specifies into which slot an element flows. A grid templates is like a
table in that the various slots are aligned in rows and columns and can
automatically adapt to each others size, and it is like absolute
positioning in that elements can be put in arbitrary slots so that the
visual order becomes independent of the document order.
The ‘::slot()
’
pseudo-element allows to style the slots (backgrounds, borders, etc.)
The ‘grid-position
’ property can be used
instead of the ‘top
’, ‘left
’, ‘right
’ and ‘bottom
’ properties from level 2 to
position absolutely positioned elements relative to a grid template, so
that they align with the content in the grid.
Grid templates can also be associated with pages in paged media, to create page templates.
Slots can also form “chains” to create non-rectangular
regions. A chain of slots is like a series of pages or columns: content is
distributed over the slots by breaking it at possible break points (see
the ‘break-*
’ properties from [CSS3-BREAK]).
The ‘::fragment()
’
pseudo-element allows to select (parts of) elements based on whether they
fall in a certain slot or not, and thus style content differently in
different slots (region-based styling).
This is a public copy of the editors' draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don't cite this document other than as 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 combines ideas from earlier drafts on Template Layout, Grid Positioning [CSS3GRID] and Grid Layout [CSS3-GRID-LAYOUT].
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.”
::slot()
’ pseudo-element
::fragment()
’
chains
’ property
display
’ or add a grid
property
*
’ vs ‘fr
’
*
’ vs ‘@
’)
fit-content
’ vs
‘auto
’ vs…
(This section is not normative.)
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 grid
with an element. Rather than letting an element lay out its descendants in
a single flow, the policy defined in this module gives an element a
grid template, which is a set of slots
aligned to an invisible grid, where each slot is a separate flow. The
descendants are given a ‘flow
’ property to designate the slot into
which they flow.
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:
Complex Web pages, with multiple navigation bars in fixed positions, areas for advertisements, etc.
Complex forms, where the alignment of labels and form fields may be easier with the properties of this module than with the properties for tables and margins.
GUIs, where buttons, toolbars, labels, icons, etc., are aligned in complex ways and have to stay aligned (and not wrap, for example) when the window is resized.
Paged displays (e.g., printed media) where each page is divided in fixed areas for different kinds of content.
Complex pages with multiple regions, where the style of the text does not only depend on the type of element it comes from, but also on the region it is displayed in.
Once a grid template has been defined, it can also be used as an
alternative coordinate system for absolutely positioned elements. Such
elements do not flow into slots, but, by using ‘grid-position
’ (instead of ‘top
’, ‘left
’ etc.) can be
aligned to grid lines and thus to the content in the grid.
But for many applications, template-based positioning makes absolute positioning unnecessary. Like absolute positioning, grid templates are 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 flowing them into a template that is very much like a table: The size and alignment of elements are governed implicitly by the rows and columns of the template, and can automatically adapt to the overall size of the element and to the content in each row and column.
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.)
<style type="text/css"> dl { grid: "ab" "cd" } #sym1 { flow: a } #lab1 { flow: b } #sym2 { flow: c } #lab2 { flow: d } </style> <dl> <dt id=sym1>A <dd id=lab1>A is een aapje <dt id=sym2>B <dd id=lab2>B is de bakker </dl>
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 { grid: "aaa" "bcd" } #head { flow: a } #nav { flow: b } #adv { flow: c } #body { flow: d } } @media all and (max-width: 500px) { body { grid: "a" "b" "c" } #head { flow: a } #nav { flow: b } #adv { display: none } #body { flow: c } }
The slots in a grid do not overlap, unless with negative margins. Here is how the “zunflower” design of the CSS Zen Garden could be done:
#container {grid: "abc"} #container::slot(a) {box-shadow: 0.5em 0.5em 0.5em; z-index: 1} #container::slot(b) {box-shadow: 0.5em 0.5em 0.5em; margin-left: -2em} #intro {flow: a} #supportingText {flow: b} #linkList {flow: 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 one another'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>bbb</div> <div class=menu>ccccc</div> </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}
We can also use a template, in which case the style sheet would contain this:
.group {grid: "abc"} .group > div {flow: a} .group > div + div {flow: b} .group > div + div + div {flow: 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 grid template, but, on the other hand, if we want the template to fit its contents, we would need to say so:
.group {grid: "abc"; width: auto}
(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}
In both styles, we can set a column to a certain size:
div.menu {width: 3em}
resp.,
.group {grid: "abc" * * 3em}
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).
(However, extra columns or rows will be created if necessary
to absolutely position elements. See the ‘grid-position
’ property.)
In both models, elements can have borders, but only in the table model can borders be collapsed, which makes setting borders easier in the table model:
.group {display: table; border-collapse: collapse} .group > div {border: solid}
resp.,
.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 {flow: c} .group > div + div {flow: b} .group > div + div + div {flow: a}
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. <p>… </div>
with this style sheet
div.section { grid: "*" "F"} .note { flow: F; content: counter(note) ".\A0" contents; counter-increment: note; font-size: smaller} .note::before { content: counter(note); vertical-align: super; font-size: larger}
results in a rendering similar to this:
The “Generated content for paged media” module [CSS3GCPM] is expected to define specific features for footnotes that are both easier and more powerful than this example.
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.
We assume a document fragment similar to this:
<div id=article> <h1>Introduction</h1> <p><img src="sunset" alt=""> <p>This is an example… <h1>More Details</h1> <p>This illustrates… <p>Then, the example… <p>Finally, this… </div>
The style sheet makes the DIV into a template element with five regions, called A, *, b, c and d. The regions are grouped into two chains: region A on its own, and the chain consisting of *, b, c and d.
#article { grid: "A A c" "A A c" "* * c" "a b c"; chains: * a b c }
The ‘*
’ is a special name. It
indicates the default slot, the
slot where content goes if it doesn't have an explicit ‘flow
’ property. We
could have used a normal letter and added an explicit ‘flow
’ property to the
children of the DIV, but by using * we don't have to. All children thus
go into region * (and continue in a, b and c as needed). The IMG element
goes into region A. We assume for simplicity that there is only one IMG
element:
#article img { flow: A }
The text in region * 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.)
As the image shows, the text of the last paragraph isn't complete and presumably continues somewhere else, but that part is outside the scope of this example. In paged media, we could attach the grid template to a page instead of an element and let the text continue on the next page; we could also make slot c into a multi-column element so that the text forms additional columns to the right of current image (see [CSS3GCPM] for some ideas), or we could allow a scrollbar on slot c.
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.
This specification follows the CSS property definition conventions from [CSS21]. Value types not defined in this specification are defined in CSS Level 2 Revision 1 [CSS21]. Other CSS modules may expand the definitions of these value types: for example [CSS3COLOR], when combined with this module, expands the definition of the <color> value type as used in this specification.
In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the inherit keyword as their property value. For readability it has not been repeated explicitly.
(This section is not normative.)
The facilities in this specification allow elements from a document to be displayed in a visual order that is to a large extent independent of the order in the document. That may have both positive and negative effects on accessibility. The positive aspect is that it allows the content in the document to be kept in logical order, so that the document is as functional as possible without the style sheet and on media where the style sheet doesn't apply. A negative aspect is that a document that has a defined tab order (the order in which elements get the focus when the tab-key is pressed) will show on the screen with a tab order unrelated to the visual order. It may be necessary to use the keyboard control features of the CSS Basic User Interface module [CSS3UI] to ensure that the tab navigation follows the visual order, or to refrain from positioning semantically related elements in different parts of a template.
The following two requirements from the Web Content Accessibility Guidelines (WCAG) 2.0 [WCAG20] are particularly relevant. See that specification for more information.
1.3.2 Meaningful Sequence: When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined. (Level A)
2.4.3 Focus Order: If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability. (Level A)
Grid templates are declared with the ‘grid-template
’, ‘grid-rows
’,
‘grid-columns
’ and ‘grid
’ properties,
defined below.
An element that has a grid template is called a grid element. More precisely: an element is a grid
element if (1) it generates a block container box [CSS21] and (2) at
least one of ‘grid-template
’, ‘grid-rows
’ or
‘grid-columns
’ has a value other than the
initial value.
Block containers are, informally, elements that can have block elements as children, such as blocks, inline blocks or table cells, but not inline elements or replaced elements.
An element's grid ancestor is the nearest ancestor that is a grid element.
Note that not all elements have a grid ancestor. E.g., the root element has none.
The number of columns of a grid element
is the number of <col-width>
values in ‘grid-columns
’ or the number of columns in
‘grid-template
’, whichever is larger.
The number of rows is the number of <row-height> values in
‘grid-rows
’ or the number of rows in
‘grid-template
’, whichever is larger.
Note that a grid element always has at least one row and one column. Those may, however, have zero size.
grid-template
’The ‘grid-template
’ property implicitly assigns
a grid to an element and defines named slots in the grid. It can also
designate a slot as the default slot
for content without an explicit flow.
Name: | grid-template |
---|---|
Value: | none | <string>+ |
Initial: | none |
Applies to: | block container elements [CSS21] |
Inherited: | no |
Animatable: | no |
Percentages: | N/A |
Computed value: | specified value |
Canonical order: | per grammar |
Each string consist of one or more asterisks (“*”), letters, periods (“.”), spaces and tabs. Each string represents one row in the template, each symbol other than a space or tab represents one column in that row. Spaces and tabs have no meaning. They may be added for readability.
The symbols in the template have the following meaning
CSS doesn't yet have a type corresponding to single
letter. The letters in this module are also used outside of strings (on
‘flow
’,
e.g.), so they should be a subset of identifiers. There is a
“nmstart” macro in the grammar, but it is not exactly what we want
here. E.g., U+0300 (“combining grave accent”) is a valid first
character for an identifier, but may not be desirable as a slot in a
template. We probably want a definition based on the principle that it
is a single letter if it looks like a single letter. This may
correspond to the notion of character cluster. (There may also
be a connection with the open issue against the CSS syntax about Unicode
normalization. We want é to match é, no matter if the author typed
U+0301 U+0065 or U+00C9.)
Multiple identical letters in adjacent rows or columns form a single slot that spans those rows and columns. Ditto for multiple “*”s. Slot names are case-sensitive, so uppercase and lowercase letters are considered to be different letters.
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 (“.”).
Each slot (letter or “*”) acts as a block element for its contents.
If the value is ‘none
’, then no
explicit slots are defined. If the element is a grid element, then the element instead
has an implicit template consisting of a
single ‘*
’ slot.
Note that an element is a grid element in this case if
‘grid-columns
’ and ‘grid-rows
’ are not
both ‘auto
’.
For example, the following two sets of style rules are equivalent:
DIV { grid-template: none; grid-rows: 10em 10em 10em; grid=columns: * * * * }
and
DIV { grid-template: "****" "****" "****"; grid-rows: 10em 10em 10em; grid=columns: * * * * }
grid-columns
’Name: | grid-columns |
---|---|
Value: | auto | <col-width>+ |
Initial: | auto |
Applies to: | block container elements |
Inherited: | no |
Animatable: | yes, between grids with the same number of tracks |
Percentages: | N/A |
Computed value: | specified value |
Canonical order: | per grammar |
The ‘grid-columns
’ property specifies the sizes
of the columns of a grid.
Where
<col-width> = <length> | <percentage> | * | <fraction> | <minmax> | min-content | max-content | auto <minmax> = minmax( <col-width> , <col-width> )
The definition of minmax isn't correct, it should only accepts certain values.
Each <col-width> sets the width of a column, the first value for the first column, the second for the second columns, etc.
If there are fewer <col-width> values than the number of columns in the element, or if the
value is ‘auto
’, the missing columns
widths are all ‘*
’.
Each <col-width> can be one of the following:
fr
’.) A fraction of the remaining space, see Fraction values below.
*
’ have the same width.
minmax(p,q)
’ is treated as
‘minmax(p,p)
’.
minmax(min-content,
max-content)
’.
grid-rows
’Name: | grid-rows |
---|---|
Value: | auto | <row-height>+ |
Initial: | auto |
Applies to: | block container elements |
Inherited: | no |
Animatable: | yes, between grids with the same number of tracks |
Percentages: | N/A |
Computed value: | specified value |
Canonical order: | per grammar |
The ‘grid-rows
’ property specifies the heights
of the rows of a grid.
<row-height> = <length> | <percentage> | * | <fraction> | <minmax> | min-content | max-content | auto <minmax> = minmax( <row-height> , <row-height> )
The definition of minmax isn't correct, it should only accepts certain values.
Note that the syntax is the same syntax as for ‘grid-columns
’
If there are fewer <row-height> values than the
number of rows in the element, or if the
value is ‘auto
’, the missing row
heights are all ‘auto
’.
Each <row-height> can be one of the following:
fr
’.) A fraction of the remaining space, see Fraction values below.
*
’ have
the same height.
When the height of the grid element is dependent on content, the result is undefined.
minmax(p,q)
’ is treated as
‘minmax(p,p)
’.
minmax(min-content,
max-content)
’.
grid
’ shorthand
propertyName: | grid |
---|---|
Value: | none | [ [ <string> [ / <row-height> ]? ]+ ] <col-width>* |
Initial: | none |
Applies to: | block container elements |
Inherited: | no |
Animatable: | see individual properties |
Percentages: | see individual properties |
Computed value: | see individual properties |
Canonical order: | N/A |
The ‘grid
’
property is a shorthand for ‘grid-template
’, ‘grid-columns
’
and ‘grid-rows
’ and is equivalent to setting
those properties as follows:
grid-template
’ is set to the list of <string> values.
grid-rows
’ is set to the list of <row-height> values, with any
omitted ones set to ‘auto
’.
grid-columns
’ is set to the list of <col-width> values, or to
‘auto
’ if there are none.
For example, the rule
grid: "abc" "abd"/4em * 10em
is the same as
grid-template: "abc" "abd"; grid-rows: auto 4em; grid-columns: * 10em;
Note the ‘auto
’ keyword that was
implied in the shorthand, but must be made explicit in the ‘grid-rows
’
property.
Does it look better with the column sizes first instead of last? There would be no need for a slash:
none | <col-width>* [ <string> <row-height>? ]+
E.g.:
grid: 5em 1em * 1em 10em "a . b . c" 2em ". . . . ." 1em "d . e . f" ". . . . ." 1em "g . h . i" 2em
Every grid element has a default slot. If there is an asterisk (“*”) in the template, then that slot is the default. If there is no asterisk, then the first letter in the template defines the default slot. If there is no letter either, then…
… define where a grid element's content goes if it doesn't have any slots at all.
For example, if the template is defined by ‘grid-template: "..." "..c" "abb" "abb"
’, then
“c” is the default slot.
If the grid has an implicit
template (i.e., ‘grid-template
’ is ‘none
’), then its single slot is the default slot.
All content of a grid element that is not inside another flow (i.e., not inside a float, not absolutely positioned, etc.) is flowed into the default slot. In particular, any text content of the grid element itself is in that default flow.
For example, in this document fragment
<DIV STYLE="grid: 'ab*'"> <IMG STYLE="flow: a" SRC="image.png" ALT="Foo"> This is an <EM STYLE="flow: *">emphasized</EM> <EM STYLE="flow: b">(note well!)</EM> sentence. < </DIV>
The three slots of the grid contain:
(The ‘flow
’ property is defined below.)
For the purpose of the calculations below, each slot (letter or “*”) in a grid has four dimensions associated with it, called MINW (“minimum width”), PREFW (“preferred width”), MINH (“minimum height”) and PREFH (“preferred height”). We can think of them as the minimum and preferred dimensions of the slot in isolation, i.e., if it wasn't constrained by other slots in the same row or column. They are defined as follows:
*
’, <fraction>
values, or any combination of those), then MINW is 0. (Note that <length> values can be
specified with ‘calc()
’ as well, see
[CSS3VALUES]].)
margin-left
’, ‘margin-right
’, etc., that is set on it
by means of the ‘::slot()
’ pseudo-element). Any ‘auto
’ margins are counted as 0 in this case.
max-content
’ (or
‘minmax()
’ with a first argument of
‘max-content
’), then MINW
is the intrinsic preferred width (see [CSS3BOX]) of the slot plus its
horizontal margin, border and padding. Any ‘auto
’ margins are counted as 0 in this case.
min-content
’ or
‘minmax()
’ with a first argument of
‘min-content
’, but no ‘max-content
’) MINW is the intrinsic
minimum width (see [CSS3BOX] of the slot, plus its
horizontal padding, border and margin.
*
’, <fraction>
values, or any combination of those), then PREFW is
infinite.
max-content
’ (or
‘minmax()
’ with a first argument of
‘max-content
’), then
PREFW is the intrinsic preferred width (see [CSS3BOX]) of
the slot plus its horizontal margin, border and padding.
*
’, <fraction>
values, or any combination of those), then MINH is 0.
max-content
’ (or
‘minmax()
’ with a first argument of
‘max-content
’), then MINH
is the intrinsic preferred height (see [CSS3BOX]) of the slot plus its
vertical margin, border and padding.
*
’, <fraction>
values, or any combination of those), then PREFH is
infinite.
max-content
’ (or
‘minmax()
’ with a first argument of
‘max-content
’), then
PREFH is the intrinsic preferred height (see [CSS3BOX]) of
the slot plus its vertical margin, border and padding.
For example, the MINW values of the slots in this grid
grid: " a a . " " b . c " auto * 10em
are as follows:
min-content
’ (because the slot
spans at least one column with a width specified as ‘min-content
’ or ‘auto
’).
min-content
’ (ditto).
The UA must choose the widths and heights of all columns and rows such that the following constraints are satisfied.
If the element has an a-priori known content height, then the sum of the heights of all rows must be equal to the element's height.
For example, the two rows in this grid must be 8em each so that the total height matches the height of the element:
div { height: 16em; grid: "a.b"/* "ac."/* }
If the grid element has an a-priori known content width, then the sum of the widths of all columns must be equal to the element's width.
For example, the three columns in this grid must be 20em each:
div {width: 60em; grid: "abc"}
*
’ must have the same height.
If we have both ‘*
’ and
‘fr
’, then ‘*
’ will be defined as ‘1fr
’ and we can drop this rule and the next.
Otherwise either these two rules or the next two must be removed.
*
’ must have the same width.
fr
’, the computed heights Hi and
Hj must be such that Hi * hj =
Hj * hi. (I.e., their heights are proportional to
their number of ‘fr
’ units.)
fr
’, the computed width Wi and
Wj must be such that Wi * wj =
Wj * Wi. (I.e., their widths are proportional to
their number of ‘fr
’ units.)
Each row that contains slots that span only one row and no slots that
span more than one row, must not be higher than the largest
PREFH of all slots in the row plus the amount needed to
vertically align the horizontal slots
that have a ‘vertical-align
’ of ‘baseline
’.
For example, the second row in this grid
grid: "a.c.." / 5em "....b" / auto
must not be taller than the height (block dimension) of slot b. The first row contains a slot that spans two rows (slot a), so this rule does not apply to that row.
Each column that contains slots that span only one column and no slots
that span more than one column, must not be wider than the largest
PREFW of all slots in the column plus the amount needed to
align the vertical slots that have a
‘vertical-align
’ of ‘baseline
’.
For example, in this grid
grid: "ac" "ab" auto *
the first column must not be wider than the PREFW of slot a. Both slots in the second column have an infinite PREFW, so this rule effectively puts no constraint on that column.
If it is impossible to choose such widths and heights, then try without constraint 1. If it is still impossible, try without constraint 2 instead. And, finally, try with both 1 and 2 dropped.
For example, the sum of the row heights in this example can never be the same as the height of the element:
div { height: 20em; grid: "a b c" / 7em "a . c" / 7em }
The first constraint is therefore ignored, the rows are 7em each and 6em of space below the grid remains empty.
If there are multiple solutions, and constraint 1 was dropped or did not apply, then the sizes must additionally be chosen such that the sum of the heights of the rows is minimized.
If there are still multiple solutions, and constraint 2 was dropped or did not apply, then the sizes must additionally be chosen such that the sum of the widths of the columns is minimized.
The calculation is intended to be symmetric in width and height (except for the case when both width and height are fixed and the grid is over-constrained, when a solution that ignores the height is tried before trying one that ignores the width).
For example, there would be multiple solutions for this grid:
<DIV STYLE="float: left; grid: 'a.b'"> <P STYLE="flow: a">Two words <P STYLE="flow: b">Only three words </DIV>
The columns must have equal width, but there is no other constraint on the width. They could be narrow:
Two
words
Only
three
words
or wider:
Two words
Only three words
or even wider still, e.g.:
Two words
Only three words
The rule to minimize height excludes the first, narrow solution. The rule to minimize width excludes the third and all wider solutions. So the second layout, the narrowest that has all words on one line, is the correct one.
(This example assumes the width of the floating DIV's containing block
is large enough. The default width of a float is actually ‘fit-content
’, and thus if the containing block is
too narrow, the result will be narrower, too, because the calculation
will have to be redone using that width as the a-priori width for the
DIV.)
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?
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 the anonymous block is a flow root (see [CSS3BOX]).
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%; grid: "a . b . c" /2em ". . . . ." /1em "d . e . f" ". . . . ." /1em "g . h . i" /2em 5em 1em * 1em 10em} #logo {flow: a} #motto {flow: b} #date {flow: c} #main {flow: e} #adv {flow: f} #copy {flow: g} #about {flow: h} </style> <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.]
This section until the next subsection is not normative.
Grids can be used in two different ways to position content. The first way is to flow content into slots (either into explicit slots identified by letters, or the default slot “*”). Each slot is an individual flow root (“establishes a block formatting context” in the terminology of CSS level 2), very much like a table cell.
The second way is to absolutely position elements using four grid lines to specify the positions of the
four margin edges of the element. Like other positioned elements [CSS21], these elements
can overlap each other and the ‘z-index
’ property applies to them.
flow
’The ‘flow
’
property adds an element to a slot.
Name: | flow |
---|---|
Value: | auto | <identifier> | ‘* ’ | same
|
Initial: | auto |
Applies to: | elements with ‘position ’ equal to ‘static ’ or ‘relative ’
|
Inherited: | no |
Animatable: | no |
Percentages: | N/A |
Computed value: | specified value |
Canonical order: | per grammar |
If the value is not ‘auto
’, the
element is added to the flow of the given slot, instead of to the flow of
its parent.
If the element has no grid ancestor, or
that grid ancestor has no slot of the given name, the property is treated
as if it were ‘auto
’.
A value of ‘same
’ means the element
is put into the same slot as the nearest preceding element in document
order that (1) has the same grid ancestor,
(2) to which the ‘flow
’ property applies and (3) whose
‘flow
’
property is not ‘auto
’.
If the letter refers to a slot that doesn't exist in the element's grid ancestor (or there is no grid ancestor) there are several possibilities:
flow: *
’ had been
specified); or not positioned at all, in case there is no grid ancestor.
All content flowed into the same slot, whether explicitly with ‘flow
’ or implicitly by
flowing into the default slot, forms a single flow, with content in
document order. The slot establishes a block formatting context and
becomes the containing block of the
resulting content flow. The boxes of elements flowed into the same slot
explicitly (by means of ‘flow
’) are each others siblings in the
slot.
The content flowed into a slot does not inherit properties from the slot.
For example, the style sheet
BODY {grid: "a." ".b"} .paris {flow: a} .london {flow: b}
with this document
<DIV CLASS=london> <P>The... <DIV CLASS=paris> <P>The... <DIV CLASS=london> <P>The... </DIV> </DIV> </DIV>
causes the second and third DIVs to be taken out of their parents. The
second DIV becomes the first child of slot a (i.e., of the pseudo-element
called ‘::slot(a)
’). The third DIV
becomes the sibling of the first DIV, because both are added to slot b
independently.
Note that ‘flow
’ applies to floating elements: they
are floated relative to their containing block, and if their ‘flow
’ property
indicates a slot in a grid, that slot is their containing block. See also
“Floating elements inside templates” below.
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 </div>
The caption can be put above the image by using a template as follows:
div.figure {grid: "aaa" ".b." * min-content *} div.figure p {flow: b} div.figure p.caption {flow: 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; grid: "a" "b" min-content} div.figure p {flow: b} div.figure p.caption {flow: 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; grid: "aaaa.bbbb" "........."/1em "cccc.dddd" "........."/1em "...ee..ff" } label[for=minv] { flow: a } input#minv { flow: b; display: block } label[for=maxv] { flow: c } input#maxv { flow: d; display: block } input[type=submit] { flow: e; display: block } input[type=reset] { flow: 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"> </form>
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.
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.
For clarity, the inner template uses different letters for the slots than the outer template. This is not required.
<style type="text/css"> body { grid: "a b" 10em *; } #nav { flow: a; } #content { flow: b; grid: "c . d . e " ". . . . . "/1em ". . f . . " * 1em * 1em *; } .module.news { flow: c; } .module.sports { flow: d; } .module.personal { flow: e; } #foot { flow: f; } </style> <body> <ul id="nav"> <li>navigation</li> </ul> <div id="content"> <div class="module news"> <h3>Weather</h3> <p>There will be weather</p> </div> <div class="module sports"> <h3>Football</h3> <p>People like football.</p> </div> <div class="module sports"> <h3>Chess</h3> <p>There was a brawl at the chess tournament</p> </div> <div class="module personal"> <h3>Your Horoscope</h3> <p>You're going to die (eventually).</p> </div> <p id="foot">Copyright some folks</p> </div> </body>
This example shows the use of ‘same
’
to put DD
elements in the same slot as the preceding
DT
.
... DL {grid: "a.b.c" * 2em * 2em *} DT.mineral {flow: a} DT.animal {flow: b} DT.plant {flow: c} DD {flow: same; margin-left: 1em} ... <DL> <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... </DL>
An alternative to ‘same
’
may be to create selectors with regular-expression-like capabilities:
‘DT.plant + DD* + DD {flow: c}
’ selects
a DD that follows zero or more DDs that follow DT.plant.
Does a percentage ‘height
’ work on an element that is flowed
into a slot? If the grid template assigns a fixed height to the slot, it
is obvious what a percentage means, but if the slot's height is
‘max-content' and an element in the slot has
'height: 110%', there is a conflict…
Trying to combine 'grid-row/column' and 'grid-row/column-span', because they should not cascade independently. (If one style rule tries to place by start/end lines, and another tries to place by span, the result of the cascade will be a mess.)
The 'grid-position-x' and 'grid-position-y' properties can absolutely position an element relative to a grid.
Name: | grid-position-x, grid-position-y |
---|---|
Value: | auto | [ <identifier> | <grid-line> ] [ + <span> | - [ <identifier> | <grid-line> ] ]? |
Initial: | auto |
Applies to: | elements with 'position: absolute' |
Inherited: | no |
Animatable: | no |
Percentages: | N/A |
Computed value: | specified value |
Canonical order: | per grammar |
Where
<grid-line> = <integer> | same | next <span> = <integer>
If the value is ’auto'‘, the element is
positioned with
’top' and ‘bottom
’ (for ‘grid-position-y
’) or ‘left
’ and ‘right
’ (for ‘grid-position-x
’, see [CSS21]. The other values mean that
the computed values of ‘top
’/‘bottom
’ or ‘left
’/‘right
’ are ignored and their used values
are set as defined below.
If the element has no grid ancestor, the
value is interpreted as if it were ‘auto
’.
An <identifier> refers to a slot in the grid ancestor.
If an <identifier> refers to a non-existent slot, the
whole value is interpreted as if it were ‘auto
’.
If <grid-line> is an integer, it refers to a grid line, i.e., the horizontal line at the edge of a row or the vertical line at the edge of a column. The top of the first row of a grid template is the horizontal grid line with number 1, the top of the second row is 2, etc. up to N+1 for a grid template with N rows. Similarly, the vertical grid lines are numbered 1 to M+1 for a grid template with M columns.
It is an error if the integer is ≤ 0.
The keyword ‘same
’ stands for the
grid line specified by the nearest preceding element in document order
with the same grid ancestor to which
‘grid-position-x
’ or ‘grid-position-y
’ applied. If there is no
such element, or if it specified ‘auto
’, then ‘same
’ stands for ‘1
’.
The keyword ‘next
’ stands for next
the grid line after the one specified by the nearest preceding element in
document order with the same grid ancestor to
which ‘grid-position-x
’ or ‘grid-position-y
’ applied. If there is no
such element, or if it specified ‘auto
’, then ‘next
’ stands for ‘1
’.
A <span> is a non-negative integer. It indicates the number of rows or columns the element spans, as defined below.
It is an error if the span is < 0.
The values are of the following forms:
<identifier> -
<identifier>
’ (twice the same identifier).
<grid-line> +
1
’ (i.e., a position and a span of 1).
Top
’ (or
‘left
’) is
set to the top (or left) margin edge of the first slot. ‘Bottom
’ (or
‘right
’) is
set to the bottom (or right) margin edge of the second slot.
Top
’ (or
‘left
’) is
set to the top (or left) margin edge of the first slot. ‘Bottom
’ (or
‘right
’) is
set to the given grid line.
Top
’ (or
‘left
’) is
set to the indicated grid line. ‘Bottom
’ (or ‘right
’) is set to the bottom (or right)
margin edge of the second slot.
Top
’ (or
‘left
’) is
set to the grid line indicated by the first number. ‘Bottom
’ (or
‘right
’) is
set to grid line given by the second number.
Top
’ (or
‘left
’) is
set to the top (or left) margin edge of the first slot. The
<span> specifies the number of rows (or columns)
spanned, i.e., ‘bottom
’ (or ‘right
’) is set to the grid line
<span> rows below (or columns to the right) of that
edge.
Top
’ (or
‘left
’) is
set to the grid line given by the first number The second number
specifies the number of rows (or columns) spanned, i.e., ‘bottom
’ (or
‘right
’) is
set to the grid line <span> rows below (or columns to
the right) of the first.
For example, these rules
DIV {grid: "ab" "cd"} P {position: absolute; grid-position-x: d; grid-position-y: a}
mean that any P spans the same rows as slot a and spans the same columns as slot d. In this case, that means it coincides with slot b. All of the following are thus equivalent:
P {position: absolute; grid-position-x: b; grid-position-y: b} P {position: absolute; grid-position-x: b + 1; grid-position-y: b + 1} P {position: absolute; grid-position-x: b - b; grid-position-y: a - a} P {position: absolute; grid-position-x: 2 + 1; grid-position-y: 1 - 2} P {position: absolute; grid-position-x: 2; grid-position-y: 1}
Use negative number to count from the right/bottom?
This needs to be worked into the constraints for the
calculation of the grid size, so that these absolutely positioned elements
also contribute to the calculation of ‘min-content
’ and ‘max-content
’.
When using <grid-line> or <span> (but
not when using <identifier>), it is possible to refer to
grid lines that do not exist in the grid declared with ‘grid-columns
’/‘grid-rows
’. In
such a case, the grid is automatically extended with the necessary rows or
columns. The sequence of sizes given by ‘grid-columns
’/‘grid-rows
’ is
repeated as often as necessary to create exactly the required number of
rows and column.
For example, you can transpose a table such as
<TABLE> <TR><TD>A1 <TD>A2 <TD>A3 <TR><TD>B1 <TD>B2 <TD>B3 ... <TR><TD>K1 <TD>K2 <TD>K3 ... </TABLE>
to display it somewhat like this
A1 B1... K1... A2 B2... K2... A3 B3... K3...
with style rules like this:
TABLE {grid-columns: auto; grid-rows: auto} TD:first-child {grid-position-x: next; grid-position-y: 1} TD {grid-position-x: same; grid-position-y: next}
ISSUE-201: Terra
Informatica's HTMLayout program
proposes an interesting shortcut: if a slot's name is a number (instead of
a letter), it refers directly to the child with that number. That child is
absolutely positioned on top of that slot and doesn't need ‘position
’,
‘grid-position-x
’ or ‘grid-position-y
’ to be set. See the
documentation by Andrew Fedoniouk and Ivan Goroun. E.g., <ul
style="grid: '2 1'"><li>one <li>two </ul>
puts “two”
on the left and “one” on the right. (Note that this requires that the
names of slots are separated by spaces.) It is thus also a shortcut for
some applications of ‘flex-order
’.
grid-position
’ shorthand propertyName: | grid-position |
---|---|
Value: | <grid-position-x> [ / <grid-position-y> ]? |
Initial: | auto |
Applies to: | elements with ‘position:
absolute ’
|
Inherited: | no |
Animatable: | no |
Percentages: | N/A |
Computed value: | specified value |
Canonical order: | per grammar |
This is a shorthand for ‘grid-position-x
’ and ‘grid-position-y
’. If
<grid-position-y> is omitted, it is the same as
<grid-position-x>.
For example, these rules
DIV {grid: "ab" "cd"} P {position: absolute; grid-position: d / a}
position any P to coincide with slot b. All of the following are thus equivalent:
P {position: absolute; grid-position: b / b} P {position: absolute; grid-position: b + 1 / b + 1} P {position: absolute; grid-position: b - b / a - a} P {position: absolute; grid-position: 2 + 1 / 1 - 2} P {position: absolute; grid-position: 2 / 1} P {position: absolute; grid-position: b}
::slot()
’ pseudo-elementThe slots of a grid element can be
individually addressed with the ‘::slot()
’ pseudo-element.
For example, the following sets the background and vertical alignment of some of the slots in a template:
body { grid: "aaa" "bcd" } body::slot(b) { background: #FF0 } body::slot(c), body::slot(d) { vertical-align: bottom }
Only the following properties apply to the ‘slot()
’ pseudo-element.
vertical-align
’ (see “vertical alignment” below)
overflow
’ (see the sections on vertical alignment and paged media below)
writing-mode
’
direction
’
box-shadow
’
box-decoration-break
’
Should ‘content
’ be allowed? or should instead
‘::slot(a)::before
’ be possible (and
ditto with ‘::after
’)? The content
would be at the start of the flow, before any elements flowed into the
slot and even before the grid element's ‘:before
’ pseudo-element, if the slot is the default slot. If content applies, then most
other properties apply, too, to set the style of that content: color,
font, text-decoration…
Should the ‘content
’ property allow ‘element()
’ from GCPM? You could then repeat the
heading of an article at the top of each slot in case the article is split
over several chained slots or several pages. (See also the issue about “continued on.”)
ISSUE-37: Can a slot have a border and if so, where is it drawn?
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
’.
Margins on slots do not collapse, neither with other slots, nor with elements inside the slot.
Margins aren't really necessary on slots. You can add
‘.
’ cells in the grid template to make
empty space.
::fragment()
’The ‘:fragment(a)
’ pseudo-element
selects the part of an element that is inside slot a (similar to how
‘::first-line
’ selects the part of an
element that is on the first line).
Inherited properties…
Non-inherited properties…
Grid elements influence the stacking order, page breaks, the position of floats, etc. of the content inside them.
The ‘vertical-align
’ property of a ‘::slot()
’ pseudo-element can
be used to align elements vertically in a slot (or horizontally, if the
slot is vertical). The effect is as if the
hypothetical anonymous block
that contains the slot's contents is positioned as defined below.
For the purpose of this section we define the tail edge and head edge of a box as a writing-mode-dependent edge as follows:
Value of ‘writing-mode ’
| Meaning of “head” | Meaning of “tail” |
---|---|---|
‘horizontal-tb ’
| top | bottom |
‘vertical-rl ’
| right | left |
‘vertical-lr ’
| left | right |
E.g., if a box is horizontal, “head edge” means the top edge.
(Note that if the content overflows the slot, it will overflow at both edges.)
writing-mode
’ and the same ‘vertical-align
’ in the same row (if the
slot is horizontal) or the same
column (if the slot is vertical). A
slot has a relevant first line, if the content has a first line
(ignoring any lines inside floats) and that first line has the same
‘writing-mode
’ as the slot itself.
For example, for a horizontal slot, this means that the
first baseline must be aligned with the first baselines of all other
horizontal slots in the row that also have ‘vertical-align: baseline
’.
0%
’ means the same as ‘bottom
’, ‘100%
’ means the same as ‘top
’, other values are
linear interpolations of these. Negative values and values over 100% are
interpreted as 0% and 100% respectively.
Note that 100% minus the percentage corresponds to the initial position of the scrolling mechanism (if any) in case the content overflows.
For all other values, the content is aligned as for ‘baseline
’.
Grid elements may be broken across pages,
columns or similar regions (including chained slots of another grid
element), subject to the ‘break-before
’, ‘break-after
’
and ‘break-inside
’ properties. In addition to
the break points listed in the Fragmentation module [CSS3-BREAK], 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?
In the terminology of [CSS3-BREAK], a slot is a fragmenter of type ‘region
’.
A forced break on an element in a slot causes the rest of the flow of that slot to continue in another page, column or slot (depending on the type of break). The following cases are special:
A forced page break causes all elements after the break (in document order) to be on a new page. On which subsequent page they fall depends on any page templates: there may not be a slot with the right name on the next page.
A forced column break only has effect if the element's multicol ancestor is a descendant (is “inside”) the element's grid ancestor.
For example, this document fragment has a column element inside a grid element. Column breaks affect the content of a single slot, but do not affect the other slots of the grid element:
<DIV STYLE="grid: 'ab' 'cd'"> <DIV STYLE="flow: a"> I'm in slot a. </DIV> <DIV STYLE="flow: b; columns: 20em"> <P>This text is in columns. <H2 STYLE="break-before: column">Heading at top of column</H2> <P>... </DIV </DIV>
For example, this document fragment has a grid element inside a column element and thus the column break on the H2 is ignored:
<DIV STYLE="columns: 20em"> <DIV STYLE="grid: 'ab' 'cd'"> <P>I'm inside slot a inside some columns. <H2 STYLE="break-before: column">No break</H2> <P>... </DIV> </DIV>
A slide presentation can be made with a template for each page (i.e., slide) and forced page break between the slides:
@page { grid: "a" / 5em "@" / * "b" / auto } h1 { page-break-before: always; flow: a } p.note { flow: b }
With a document similar to this: (fragment)
<h1>Slide 1 title</h1> <ul> <li>Topic one </ul> <h1>Slide 2 title</h1> <ul> <li>More topics </ul> <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; grid: "a"/5em "*" "b"/intrinsic; page-break-before: always} h1 {flow: a} p.note {flow: b}
With a document similar to this: (fragment)
<div class=slide> <h1>Slide 1 title</h1> <ul> <li>Topic one </ul> </div> <div class=slide> <h1>Slide 2 title</h1> <ul> <li>More topics </ul> <p class=note>Note the note </div>
Slots are stacked in the order they are listed in ‘grid-template
’ (order of their top left
corners). ‘z-index
’ applies. The general rules for stacking contexts [ref in
CSS3?] apply.
This example uses ‘z-index
’ and negative margins to make the
middle slot partly overlap the other slots:
body { grid: "a.b" ".c." "d.e"; height: 240px; width: 240px } ::slot(a) { background: #0C0 } ::slot(b) { background: #C00 } ::slot(c) { background: #FD0; margin: -20px; z-index: 1 } ::slot(d) { background: #00C } ::slot(e) { background: #A0A }
An element may be flowed into a slot and be a floating element at the same time. The following cases must be distinguished:
float
’
specifies that the element floats to the top or bottom of the page (in a
horizontal writing mode) or the left or right of the page (in a vertical
writing mode), the slot act as the page. (I.e., the element floats to the
top, bottom, etc. of the slot, not of the page.
float: footnote
’ is at the bottom of
the slot, not of the page. The @footnote at-rule can position the
footnote area at other places, such as the top, but always inside the
slot.
The ‘@footnote
’ at-rule
from [CSS3GCPM]
needs to be extended to apply to slots: ‘@footnote
:first::slot(a)
’ is the footnote area of slot a on the first
page.
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 syntax of a page-based template is the same as that of an
element-based one, but the declaration appears in an ‘@page
’ rule.
In a page-based template, the height and width are typically known (defined by the output media and the margin boxes, see [CSS3PAGE]). And content that overflows a slot typically is not clipped (or hidden behind a scrolling mechanism), but is continued on a subsequent page.
Because the grid template is not attached to an element but to a page, it is not scoped. The slot names are global, although they can be hidden to elements that have a grid ancestor that uses the same slot names.
This modifies the rules for ‘flow
’ and ‘grid-position
’: if these properties refer
to a slot that is not found in a grid
ancestor, they refer instead to a slot in a page template (if there
is one and it has a slot of that name).
Similarly, a ‘grid-position
’ that refers to grid lines
by number, when set on an element that has no grid ancestor, refers to grid lines of the page
template instead, if it exists. But unlike an element-based template, a
page-based template is not automatically grown if ‘grid-position
’ refers to a grid line that
was not declared in the ‘grid
’ property. Instead, ‘grid-position
’ is ignored.
Should we simplify page-based templates to only allow <length> and * as row heights and
column widths? (And treat illegal sizes as ‘*
’?)
@page :first {grid: "abc" "def"} @page {grid: "def"} body {flow: e} h1 {flow: b}
A page that has a grid template does not have a footnote area [CSS3GCPM]. Instead each slot in the grid template has its own footnote area.
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 [CSS3-BREAK]. 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 UA should display the content on a separate page.
Or: 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 {grid: "a" "*"} @page {grid: "*"} h1 {flow: a}
Note that “page masters” (sequences of different templates for sequences of pages) can be made with the selectors defined in [not yet decided].
Both page-based and element-based templates can be used in the same document.
@page {grid: "a*"} :lang(fr} {flow: a} div.special {grid: "abc" "abd"}
Here is a page as one might find in a newspaper. It combines a layout template with multicolumn layout.
@page :first { grid: "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 {flow: a; border-bottom: thick; margin-bottom: 1.5em} #toc {flow: b; margin-right: -1.5em; border-right: thin; padding-right: 1.5em} #leader {flow: c; columns: 4; column-gap: 3em} #art1 {flow: d; columns: 4; column-gap: 3em; border-top: thin} #art2 {flow: e; columns: 2; column-gap: 3em} #art3 {flow: 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 break-content property? ‘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}
’
chains
’ propertySlots must be rectangular, but the appearance of non-rectangular slots can be achieved to some 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 |
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
<DIV> <P ID=first>... <P ID=second>... </DIV>
Here is a paragraph shaped as a circle:
p { width: 12em; grid: ". . . . @ @ . . . ." / 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 { grid: "aaaaaaa.ddddddd" "aaaaaaa.ddddddd" "aaaaaaa.ddddddd" "aaaaaaa.ddddddd" "bbbb.......eeee" "bbbb.ggggg.eeee" "bbbb.ggggg.eeee" "bbbb.ggggg.eeee" "bbbb.......eeee" "ccccccc.fffffff" "ccccccc.fffffff" "ccccccc.fffffff" "ccccccc.fffffff"; chains: a b c d e f } @page::slot(g) { vertical-align: middle } body { flow: a } h1 { flow: g }
Note: For more analysis 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:
grid: "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. But the CSS WG is
considering a new property ‘wrap-flow
’ for absolutely positioned
elements that would allow, e.g.: ‘p {position:
absolute; top: 1fr; left: 1fr; width: 1fr; height: 1fr; wrap-flow:
both}
’ to absolutely position a P element on top of a
template element and cause the content of the element under it to wrap
around it as if it were a float [CSS3-EXCLUSIONS].
Note that a slot can have overflowing content even if it is part of a chain: it can have content that is too wide but cannot be broken.
The ‘break-before
’, ‘break-after
’
and ‘break-inside
’ properties have values that
control breaking of content between slots in a chain (in particular
‘region
’ and ‘avoid-region
’, see [CSS3-BREAK]).
Note that, as defined in “Breaking grid elements across pages or columns” above, a slot is a fragmenter of type region in the terminology of [CSS3-BREAK].
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:
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.
The following sections contain some of the use cases and design decision that led to this module and influenced its evolution.
(This section is not normative.)
The following types of use cases were considered for template-based layout.
Standard Web pages.
Grids and other table-like layouts. This includes grid layouts, frame layouts and table-like subdivision of a rectangular area.
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.
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).
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:
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.
the binding mechanism – the way to specify that a given element (and its descendants) are to be placed in a given layout cell.
the property distribution mechanism – the way to put properties onto the layout structure and the cells within it.
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:
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.
The binding of content to cells is handled by the ‘position
’
property which identifies a cell to which the content is bound.
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.
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.
(This section is not normative.)
The following is a partial list of design decisions and some arguments for and against each choice:
Named slots are very easy to understand and use. Experience with the draft showed that everybody who sees an example immediately understands what it means. Moreover, there is no need to use numbers or to count.
But it is different for absolutely positioned elements that use the grid. Those elements do not belong to a slot, they are merely placed on top of it, overlapping what is already there and each other.
Also, if grids are automatically extended with extra rows and columns (see below) based on content, then those extra rows and columns cannot have names and must (probably, see below) be referred to by number.
In this specification, named slots are used to create flows of content, while numbers are used for absolute positioning, although names can be used there too, if the author prefers.
The set of single letters is finite. And even if Unicode has many symbols, typing them may not be easy. Letters also do not permit to give a hint as to a slot's function (“heading,” “footer,” “advertisement”…).
On the other hand, any Unicode character can be typed as an escape, so if you run out of letters on the keyboard, you can always make a template like this:
DIV {grid: "\1001\1002\1003" "\1001\1004\1005\1006"} DIV H1 {flow: \1001}
In practice, it is also hard to come up with meaningful identifiers and so single letters require less thinking. And if you always have single letters, you don't need spaces between them either, which makes big templates easier to read.
This specification therefore uses single letters (i.e., on ‘grid-template
’; the syntaxes of ‘flow
’ and ‘grid-position
’ are the same either way).
display
’ or add a
grid propertyGrids can be defined on elements such as table cells, blocks, inline
blocks or list items, but not on elements such as tables or, inline
elements. That can be expressed in the syntax by adding the grid to the
‘display
’
property: ‘display: inline-block "abc"
"abd"
’ is valid, but ‘display: inline
"abc" "abd"
’ would not be. Or it can be expressed by an
implicit dependency between properties: ‘display:
inline-block; grid: "abc" "abd"
’ has a grid, but ‘display: inline; grid: "abc" "abd"
’ ignores the
grid. (In this case it is actually the computed value of ‘display
’ that
applies, so, e.g., if the element floats, it would be a block and thus
have a grid.)
The Multicol specification uses the latter model: ‘columns
’ is a
separate property and only applies if the element is a block container. Given that
precedent, it seemed reasonable to do the same here.
Style rules can specify both a grid and columns for the same element:
DIV {columns: 20em; grid: "aabccc"}
The specification could say that grids don't apply to column elements, or vice versa, or it could say that the columns apply to contents of the DIV, after it has been flowed into the default slot. This last option seemed the most useful. It is consistent with other elements that flow into a slots: they, too, can have columns.
It is convenient to specify the grid as the value of a single property.
It puts the column and row sizes immediately next to the rows and columns
they apply to. The typical column widths can either be omitted or are
short values like ‘*
’ and ‘1em
’, and they fit easily in one line.
But if a grid has very many columns, or their sizes are complex (with
many ‘minmax()
’ and ‘calc()
’ values, e.g.), it may be more readable to
separate the slot names from the column sizes.
Also, separable properties for row and column sizes makes is easier to specify a transition/animation on them,, because you don't have to repeat the slot names (which cannot animate).
For those reasons, this specification defines the ‘grid
’ property as a
shorthand, at the cost for authors of having to learn four new properties
instead of one (or zero, if the grid had been added to display (see above).
If the grid template can also be specified with individual properties,
how many columns & rows does it have if those properties contradict
each other? Does the template (if not ‘none
’) determine the number of columns or the
maximum of the template and the list of sizes? E.g.:
Specified values | Meaning if the template prevails | Meaning if the maximum value is used |
---|---|---|
grid-template: "a b c"; grid-columns: * * * * * |
grid-template: "a b c"; grid-columns: * * * |
grid-template: "a b c . ."; grid-columns: * * * * |
The former is consistent with the model for ‘background-image
’ and ‘background-size
’. However, unlike for
backgrounds, where a size without an image makes no sense, in this case a
size without a slot name can make sense: it can represent empty
space (‘.
’) of the given size.
What is more likely: that people consciously specify empty rows and columns without putting dots in the template (to save typing or to avoid typing too many dots), or that people mistakenly add a size too many?
The specification currently sets the number of rows and columns to the maximum of the three properties.
*
’ vs ‘fr
’ISSUE-127:
It is very common for the columns of a grid to have all the same width.
That is because the slots in a grid, although of different widths
themselves, typically are multiples of some fundamental measure. And thus
equal columns is the default in the current syntax. And if it needs to be
specified explicitly which columns have the same width (e.g., because
there are also other columns in the grid) then the symbol for it is short:
‘*
’. This is ideal for slots whose
widths are small multiples of the fundamental measure. E.g., the widths of
slots a, b and c in the following grid relate to each other as 1:3:2:
grid: "a b b b c c" "a . . . c c"
However, if the ratios of the slots are ratios of larger numbers, the notation may become long. E.g., to make slots a and b with ratio 10:11, you would have to make 21 columns:
grid: "aaaaaaaaaabbbbbbbbbbb"
It needs to be investigated if such ratios are frequent. (They don't seem to occur in printed magazines.) And if among the ratios that do occur, even if infrequently, there are some would be impractical to write in this way.
Assuming another notation is needed, it could be made by prefixing a
number (e.g., ‘7* 10*
’) or, to make the
notation look more like a dimension, by creating a special unit
‘fr
’ (‘e.g.,
’3.5fr 5fr', which is the same as 7 + 10 stars).
If ‘fr
’ is added, it could either be
in addition to ‘*
’ or instead of
‘*
’. In the former case, ‘*
’ = ‘1fr
’.
Unless it is shown that the notation with only ‘*
’ is not practical in real cases, it seems better
to neither introduce numbers (‘7*
’) nor
units (‘3.5fr
’). It would give too many
different ways to write the same grid, causing authors and readers of
style sheets to have to think longer about each grid. (E.g., ‘grid: "abbbcc"
’ could then also be written as
‘grid: "abc" 1* 3* 2*
’ or ‘grid: "abbbc" 0.5fr 0.5fr 0.5fr 0.5fr 1fr
’, etc.)
For the moment, the specification allows both the ‘fr
’ and * notations.
The main purpose of grids is to improve on absolute positioning for displaying elements in a different visual order. You typically know how many positions you need in advance.
If you don't need to change the visual order, then table layout can often align the elements sufficiently.
However, if table layout isn't possible (there are not enough elements in the source to create the necessary table rows, the control over the size of table cells is too limited, or you want a column-major table), it may be useful to use a grid in a similar manner to a table: the number of rows and columns is not specified in the style, but depends on the number of elements that are put in the grid.
E.g., you could transpose a table with an unknown number or rows like this:
<TABLE> <TR><TD>A1 <TD>A2 <TD>A3 <TR><TD>B1 <TD>B2 <TD>B3 ... <TR><TD>K1 <TD>K2 <TD>K3 ... </TABLE>
into a tabular display with an unknown number of columns somewhat like this:
A1 B1... K1... A2 B2... K2... A3 B3... K3...
with style rules like this:
TABLE {grid-columns: auto; grid-rows: auto} TD:first-child {grid-position: next / 1} TD {grid-position: same / next}
This uses keywords instead of numbers, as described in “Automatic placement of elements” below.
What is the size of the added rows and columns? The example above assumes the size of the single, specified grid cell is simply repeated. There could also be a marker in the list of sizes to indicate which set of sizes is repeated. Or there could be a separate property with the list of sizes that is repeated for all added rows and columns.
It would probably be difficult to specify that any number of columns of size A can be added, but that the last column must have size B…
The current specification specifies that extra rows and columns are
added when needed for absolute positioning (‘grid-position
’). It is not possible to
automatically create new, anonymous flows. (But sometimes you can use
multi-column elements to do that, and possibly grid templates can be
attached to columns, via a ‘::column
’)
pseudo-element, see [CSS3GCPM].)
Non-rectangular slots, such as
grid: "a a a" "a a ." "a . ."
are probably something for level 4. Or maybe the Exclusions module can be used instead.
Many layouts found in magazines can be handled with multi-columns [CSS3COL] (possibly extended with ideas in GCPM [CSS3GCPM]) or with multi-column elements inside a grid, but some more complicated designs appear to require chained slots (and some would be easier to specify that way than with columns).
grid: "A A E" "A A E" "B B E" "C D E"; chains: B C D E
Also, when grids are applied to pages (see “Page grids” below), it is essential that slots are connected to slots on the next or some subsequent page, so that the overflow can find a place.
But this could be a feature for level 4.
Typically in magazines, each page has a slightly different layout of slots, although they are all based on the same set of columns, usually between 3 and 6. It is difficult to specify the grids of all pages as a single long grid on the BODY element; and indeed impossible if you don't know how many pages use each kind of layout.
Applying grids to ‘@page
’ is an
alternative. It has a few issues:
@page news
{…}
’), a way for an element to say it needs to start
on a specific kind of page (‘break-before:
page(news)
’ or ‘break-before; always;
page: news
’), and a way to say which style follows which
(‘@page news-odd {next: news-even}
’).
This is probably for level 4.
Slots can have properties of their own: background, overflow, writing-mode, direction, box-shadow, margin, border, padding. What else?
For ‘vertical-align
’, see “Vertical alignment inside slots” below.
This specification also allows ‘z-index
’, because then you can give a slot
negative margins and have it partially overlap some other slot.
‘Wrap-flow
’ (from CSS Exclusions and
Shapes) could be useful for slots with negative margins, too.
‘Content
’
might be useful, but is maybe too powerful: you could write a whole
document, with proper styling, in a style sheet and would only need an
empty source document.
By means of a new pseudo-element, style could be applied to only the
part of an element that is inside a certain slot (similar to how
‘::first-line
’ applies style only to
the part of an element in the first line of a paragraph):
P::fragment(a) {font-size: large}
This looks like a level 4 feature.
A grid can contain vertical text, but the grid itself probably doesn't need to be rotated or flipped. Indeed, it would be confusing if it did. In other words, the following element has vertical text in the top right slot and an image in the bottom right slot:
<DIV STYLE="grid: "a*" "ab"; writing-mode: vertical-rl"> Some text here... <IMG STYLE="flow: b"...> ... </DIV>
In this specification, a grid template is always laid out with the first row at the top and the first column on the left. But the slots themselves can have a writing mode (by default the one “inherited” from the grid element).
*
’
vs ‘@
’)The symbol ‘*
’ seems a good choice,
as the concept of default is somewhat similar to the concept of wildcard.
The ‘*
’ is also used to set the size of
rows and columns, but the context is probably enough to avoid confusion.
The most flexible model for positioning content in a grid is to consider the slot as a flow, which can contain zero, one or more elements and even anonymous content. This is the same concept as a table cell: the cell also is a separate flow that can contain several elements as well as anonymous content.
An element inside a slot thus has its size determined as an element in normal flow. E.g., if you set a background on it, the background covers the element only, not the whole slot. (But the slot has its own background property for that.)
But you may also want to use the grid as a coordinate system for
absolutely positioned elements, which then overlap with the contents of
the grid (above or below it, depending on ‘z-index
’).
And, as “Automatically add rows and columns” above explains, you may want a table-like display of elements that are neither absolutely positioned nor flowed, but the table properties aren't powerful enough.
Those two ideas can be added to the grid template model: the declaration
of the grid is reused, but instead of using ‘flow
’ to position an element into it, the
element is absolutely positioned on top of it. But unlike the absolute
positioning in level 2, this positioning is allowed to influence the size
of the grid element on which it is positioned.
There are two ideas for how to do this. One idea is to define a special
kind of unit, ‘gr
’, which is only
defined for elements that have a grid
ancestor, and which can be used on the ‘top
’, ‘right
’, ‘bottom
’ and ‘left
’, properties of
absolutely positioned elements. ‘left:
2.25gr
’ means the position is in the third column, one
quarter of the way towards the fourth column.
Another way is to define a new property ‘grid-position
’ (shorthand for ‘grid-position-x
’ and ‘grid-position-y
’), which, if set,
overrides ‘top
’, ‘left
’, etc. and which takes numbers or
names of slots (up to four of them, to set the four sides).
Yet another way is to extend ‘top
’, ‘left
’, etc., with unitless values (meaning
the n'th grid column or row) and letters (meaning the appropriate edge of
the slot of that name).
This specification adds a ‘grid-position
’ property, which overrides
‘top
’,
‘right
’, etc.
When it is used, it also indicates that the element takes part in the size
calculations of the rows and columns it is put on top of.
If you want a flow that overlaps with a grid element (i.e., absolutely positioned on top of it), but that flow doesn't correspond to an element in the document you could create a pseudo-element that is like an “absolutely positioned slot:”
DIV::slot(z) {position: absolute; grid-position: 2 / 2}
Like other ‘::slot()
’ pseudo-elements, it applies to grid elements only (the DIV in this example must
be a grid element), but unlike other ‘::slot()
’ pseudo-elements it doesn't style an
existing slot, but implicitly creates a new one. (It is some kind of error
if the name ‘z
’ already exists in the
grid template.)
Then you can flow other elements into this slot:
.note {flow: z}
This mechanism is pretty difficult to understand. Experience shows it is also difficult to explain and in a style sheet it is difficult to recognize. What are the use cases (that can't be done with negative margins, absolute positioning, etc.)? This specification does not allow the creation of arbitrary, absolutely positioned pseudo-elements. If needed, it could be added in level 4.
If you position elements absolutely (with ‘top
’, ‘left
’, etc. or with ‘grid-position
’, see “Flowing vs absolutely positioning content in a
grid” above), you can use numbers to refer to grid lines: from
‘1
’ (the left edge of the first column)
to N+1 (the right edge of the last column) and ditto for rows.
You can also refer to the edges of slots, for an extra level of
indirection and to avoid the need for numbers.
It has been suggested to create a mechanism to assign arbitrary names to
grid lines, even multiple aliases for the same grid line. You could then
absolutely position an element at grid line ‘foo
’ (e.g., ‘grid-position:
foo / 1
’) and later assign that alias ‘foo
’ to a different grid line without having to
change the style rules that use it. E.g., the following could make the
name ‘a-line
’ an alias for the number 2
and ‘b-line
’ an alias for the number 4:
/* Create a 7x2 grid template */ DIV {grid-columns: * a-line * * b-line * *; grid-rows: * *} /* Put H2 at cell x=4, y=2 */ DIV H2 {position: absolute; grid-position: b-line / 2}
(This could also use strings instead of identifiers, for even more flexible names.)
This turns out to be very difficult to explain to users, partly because of the syntax, partly because of the indirection, which comes on top of the inherent indirection that CSS already requires (the style rules are in a style sheet, not on the elements they apply to) and the indirection of specifying a position indirectly by referring to an abstract grid.
Also, the number of usages of ‘grid-position
’ (for a given grid) is not
likely to be so big that a symbolic name for a grid line is necessary.
Moreover, this is easy to handle with a macro processor.
This specification does not include a mechanism to assign aliases to grid lines.
If elements are absolutely positioned relative to a grid (with ‘top
’, ‘left
’ or ‘grid-position
’, see “Flowing vs absolutely positioning content in a
grid” above), and especially if the grid can automatically grow (see
“Automatically add rows and columns”) it might
be useful to position elements relative to the last row or column,
independent of how many rows or columns the grid element has. That could
be done with negative numbers:
grid-position-x: -1
This specification does not allow positioning from the end. If uses cases are found, it could be added in level 4.
Grids are typically very regular (see also ‘*
’ vs ‘fr
’ above). E.g., if you specify the margins
between slots in the template (rather then with a ‘margin
’ property on
the slots), you often end up with a grid similar to this:
grid-template: "a.b.c.d.e.f"; grid-columns: * 1em * 1em * 1em * 1em * 1em *
Even for the columns of broadsheet newspapers (6–8 columns), that still fits easily on one line, even with margins between the columns. But if the grid gets even longer, there may be a need for abbreviations, e.g.:
grid-columns: * repeat(1em *, 5)
or
grid-columns: * (1em *)[5]
or
grid-columns: * 5//1em *//
This makes the syntax harder to learn and read, though. So it needs some good use cases first. This can be postponed to level 4.
fit-content
’ vs ‘auto
’ vs…Column sizes can have an exact size or a minimum and maximum size, by
means of ‘minmax()
’. A common case is
probably ‘minmax(min-content,
max-content)
’. (Is that really true?) Should that common case
have its own keyword? If so, should that keyword be ‘fit-content
’?
‘fit-content
’ in the Box Module is
defined as something else, viz., min(max(available width, ‘min-content
’), ‘max-content
’)).
In this specification, ‘auto
’ (not
‘fit-content
’) is allowed for column
and row sizes and has the meaning of ‘minmax(min-content, max-content)
’.
The content of a slot can be vertically aligned with ‘vertical-align
’, exactly like the content
in table cells. (Despite the name, it would, of course, be horizontal
alignment if the slot's writing mode was vertical.)
There could also be a property that applies exclusively to grids
(grid-slot-align?), just like Flexbox proposes an alignment property that
applies exclusively to flex items (‘flex-item-align
’). But why should users learn
a new property when ‘vertical-align
’ fits so well?
Looking beyond tables, flex boxes and grids, there is also a need for
vertical alignment of content in normal blocks (when those blocks have a
height that does not depend on their contents). There might thus also be a
new property that applies uniformly to all cases. E.g.: ‘block-align: top | bottom | middle | baseline |
<percentage> | <length>
’, where
‘baseline
’ simply means ‘top
’ everywhere outside grids
and tables. (A separate question is if it would override ‘vertical-align
’ in tables). Or ‘vertical-align
’ itself could be
generalized to apply to all block
container boxes (although the meaning would be ambiguous on
‘inline-block
’).
Given how little progress has been made on this generally applicable
property, the present specification just reuses ‘vertical-align
’. If a differently named
property is developed after the grid template module becomes a REC, then
whatever interaction it has with ‘vertical-align
’ would apply to slots, too.
Elements can be centered in, or aligned to a side of, their parent with
‘auto
’ margins. But this doesn't always
work: for many combinations of ‘width
’ and ‘direction
’, the
auto margins are ignored. There may thus be a new property (‘block-align: center
’?) or value (‘margin: any
’?) in the future for correct alignment
and centering.
Or should there be an alignment property that only applies to grid
slots? ‘grid-slot-align
’?
This specification defines nothing, in the expectation of a general solution in the future.
Do ‘auto
’ margins on slots (e.g.,
‘::slot(a) {margin: auto}
’) do
anything? Or are they simply 0?
[CSS3GCPM] defines “page floats” (which are slightly misnamed, because they cause floats to float not just to the top or bottom of a page, but also to the top or bottom of a column in certain contexts). What do they do in slots?
This specification treats a slot similar to a column, e.g., ‘float: top
’ means the top of the slot, not of the
page. Similarly, if slots are chained, then the
float modifiers select the next slot, not the next page.
The ‘break-before
’, ‘break-after
’
and ‘break-inside
’ properties in the draft of
February 2012 (see [CSS3-BREAK]) have keywords
‘region
’ and ‘avoid-region
’. Should they be called ‘slot
’ and ‘avoid-slot
’ instead?
There may be cases where elements are to be placed based on where the
previous elements was placed, which isn't always expressible with a clever
selector. An example is placing DD elements in the same slot as the
preceding DT element. (Note that there may be more than one DD associated
with a single DT, so a selector such as ‘DT +
DD
’ doesn't work. The selector ‘DT ~
DD
’ doesn't work either, because it selects DDs that belong
to the next DT, too.).
A keyword may help: ‘flow: same
’.
In some cases, elements may need to be placed in the next column or row after the previous element. If there are cases where rows or columns need to be added automatically based on content, those are probably also the cases where element are to be placed in the “next” row or column w.r.t. to the preceding element.
E.g., with a keyword: ‘grid-position:
next/same
’ (for “next column, same row”).
This specification defines ‘same
’ on
‘flow
’ and
‘grid-position
’ and ‘next
’ on ‘grid-position
’ only, because so far there
are no use case for ‘next
’ on ‘flow
’.
Summary of major changes since the 29 November 2011 draft:
display
’, the grid template is now
specified with a new property, ‘grid
’, to be consistent with ‘columns
’ in the
multi-column specification [CSS3COL], and also to allow the
grid to be a shorthand for more primitive properties: ‘grid-template
’, ‘grid-rows
’ and
‘grid-columns
’, which makes animations
easier to specify.
fr
’ unit
as an alternative to * on row and column sizes (and an issue about
whether these units are useful enough).
gr
’ unit as a means to
absolutely position elements on a grid and instead added a special
property, ‘grid-position
’ (shorthand for ‘grid-position-x
’ and ‘grid-position-y
’).
chains
’ property to level 4 of this
module. (In theory, it shouldn't be more difficult for a UA to balance
content in a chain of slots than in a chain of columns, but it requires
some new code, nevertheless.)
@page
’) to level 4. The scope of slot names,
automatic chaining of slots on different pages, and especially the
question of how to create more than three page templates (‘:first
’, ‘:left
’ and ‘:right
’) need more investigation.
chains
’ property)
or page-based templates.
fit-content
’
to ‘auto
’. The former has a specific
meaning in [CSS3BOX], which is related, but
not the same.
page-break-*
’
properties and to [CSS3PAGE] have been replaced with
references to ‘break-*
’ properties and
the new [CSS3-BREAK] module.
vertical-align
’.
vertical-align
’ to apply to all writing
modes.
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:
Other references:
Property | Values | Initial | Applies to | Inh. | Percentages | Media |
---|---|---|---|---|---|---|
chains | none | <letter>+ [ , <letter>+ ]* | none | template elements | no | N/A | visual |
flow | auto | <identifier> | ‘*’ | same | auto | elements with ‘position’ equal to ‘static’ or ‘relative’ | no | no | N/A |
grid | none | [ [ <string> [ / <row-height> ]? ]+ ] <col-width>* | none | block container elements | no | see individual properties | see individual properties |
grid-columns | auto | <col-width>+ | auto | block container elements | no | yes, between grids with the same number of tracks | N/A |
grid-position | <grid-position-x> [ / <grid-position-y> ]? | auto | elements with ‘position: absolute’ | no | no | N/A |
grid-position-x, grid-position-y | auto | [ <identifier> | <grid-line> ] [ + <span> | - [ <identifier> | <grid-line> ] ]? | auto | elements with 'position: absolute' | no | no | N/A |
grid-rows | auto | <row-height>+ | auto | block container elements | no | yes, between grids with the same number of tracks | N/A |
grid-template | none | <string>+ | none | block container elements [CSS21] | no | no | N/A |