[css3-grid-layout] Interaction of "gutters" and automatic item placement

The automatic item placement algorithm works very well when attempting
to flow a list of items into a grid, but it fails when you want the
grid to have "gutters" between the items.

Here's a specific use-case.  Say you have the following markup:

<container>
  <item />
  <item />
  <item />
  ...
</container>

You'd like to flow these items into a grid, 4 per row.  The following
style works:

<style>
container {
  display: grid;
  grid-columns: 1fr[4];
  grid-flow: rows;
}
</style>

The <item>s will automatically flow into the grid, filling each row
completely before starting a new one.  Perfect!

However, if you want a gutter between the cells, as you often do,
you're screwed.  The naive way to define gutters is this:

container {
  grid-columns: 1fr 10px 1fr 10px 1fr 10px 1fr;
}

This is a little verbose, but whatever.  This works if you explicitly
position things only into columns 1, 3, 5, or 7, and remember to make
your "two-column" stuff actually span 3, your "three-column stuff"
actually span 5, etc.  However, the automatic placement algorithm will
screw things up, and attempt to place 7 items per line, with three of
them in the "gutter" columns.

You can get around this by throwing more code at the problem:

<style>
container {
  display: grid;
  grid-columns: 1fr 10px 1fr 10px 1fr 10px 1fr;
  grid-flow: rows;
}

container > :nth-child(4n+1) { grid-column: 1; }
container > :nth-child(4n+2) { grid-column: 3; }
container > :nth-child(4n+3) { grid-column: 5; }
container > :nth-child(4n+4) { grid-column: 7; }
</style>

But this is ugly and silly, and is *still* incompatible with gutter
rows, because there's no way to tell the grid placement algorithm to
"skip" rows.  (You can't rely on the implicit modulus operation that
got you out of the columns problem, since you need integer division
instead, and even with calc() you don't have access to the element's
child index.)

Gutters are very common in grid systems (for example, see the very
popular fluid grid in Bootstrap
<http://twitter.github.com/bootstrap/scaffolding.html#fluidGridSystem>),
so we should support this use-case.

I suggest a "grid-gutters: <length> <length>?;" property. (Actually it
would be a <track-breadth> without the keywords.)  This establishes
gutter columns and rows, which take part in sizing, but can't have
elements placed inside of them, or be addressed directly in any way.
(Basically, this is identical to the border-spacing property for
tables.)

This simplifies the example considerably:

<style>
container {
  display: grid;
  grid-columns: 1fr[4];
  grid-gutter: 10px; /* column and row gutter are both 10px */
  grid-flow: rows;
}
</style>

To put something in the second column, you just say "grid-column: 2;",
not "grid-column: 3;".  To make it span 3 columns, you say
"grid-column-span: 3;", not "grid-column-span: 5;".  Etc.  We're back
in the simple situation we had originally, but now we have gutters
separating the cells.

Grid lines gain a slight wrinkle now, since grid cells are no longer
necessarily touching.  This can be easily and reasonably addressed,
though - the grid line still refers to the edges of the two
surrounding cells, and the "correct" cell is chosen automatically.  If
a grid line name is provided as the first token to grid-position, it
refers to the start/before edge of the cell *following* the grid line.
 If it's provided as the second token, it refers to the end/after edge
of the cell *preceding* the grid line.  (If this sounds confusing,
don't worry - it's definitely the obvious solution unless you really,
for some strange reason, want to position an item so that it expands
into a gutter. In practice, nobody really wants to do this.)

As a practical application, with this change Twitter Bootstrap could
change its fluid grids to the following:

.row-fluid {
  display: grid;
  grid-columns: 3fr[12];
  grid-gutter: 1fr;
  grid-flow: rows;
}
.span1 { grid-column-span: 1; }
.span2 { grid-column-span: 2; }
.span3 { grid-column-span: 3; }
...
.span12 { grid-column-span: 12; }

They can't yet replicate their ".offsetX" classes, but I don't think
those are necessary - it seems like they exist only because they don't
have the ability to specify exactly which column something should go
in, so they use offsets to simulate this.  Grid appears to solve this
problem adequately already.

~TJ

Received on Wednesday, 28 March 2012 00:12:45 UTC