Subgrids has become a hot topic on the past weeks, mostly due to an article by Eric Meyer called “Subgrids Considered Essential”, that shows some examples where subgrids can be really useful. Which is somehow based on a previous post by fantasai on the same topic. Also Rachel Andrew has talked about subgrids on her blog and her last ebook about Grid Layout (which is quite handy to get an introduction to grid syntax and main features).
As you probably know, Igalia has been working on the CSS Grid Layout implementation on Chromium/Blink and Safari/WebKit for a while. As implementors we thought it would be nice to share our feedback on this topic, so this week the team working on Grid Layout (Sergio, Javi and myself) arranged a meeting to review subgrids feature. These are our initial thoughts about it and a first draft proposal about a possible implementation.
State of art
Subgrids feature allows us to create nested grids that share lines with the grid container. We just define the size of the tracks on the main grid container, and the subgrid use those sizes to layout its items.
In a grid, only direct children are grid items and can be positioned on the grid. We can mark one of those items as subgrid, and then the subgrid’s children will be like regular items for the main grid. This is pretty hard to explain with words so we’ll follow up with some examples in the next section.
The feature has been marked as “at-risk” in the specification since January 2014 Which means that it could be moved to the next level (or version) of the spec.
Current situation is that none of the grid implementations (nor any web engine, neither any polyfill) support subgrids yet. Mostly because it’s a pretty complex feature and implementors have been focused on other parts of the spec.
In order to understand what subgrids are, let’s explain a few use cases. The canonical example for subgrids feature is a regular form defined using a list:
Ideally we’d like to define a grid with the labels on the first column
and the inputs on the second one.
If we define the
<ul> element as a grid container,
we’ll need to define the
<li> as subgrids to be able to place
the labels and inputs as desired.
Without subgrids we’d need to remove the list
<div> and removing
flattening our HTML and losing the semantic structure,
which is really bad from the accessibility point of view.
With subgrids support we could use the following CSS:
For this particular purpose, we could be using
(which is only supported in Firefox so far) instead of subgrids.
display: contents; to the
we’ll have the very same result.
On the other hand, another of the subgrids examples that we can find out there is a catalog of shop items. Imagine that those products are composed by title, picture and description.
The HTML of each item would be something like this:
And imagine that we use the following CSS:
The goal is that each product appears in a subgrid of 3 rows, that way the titles and descriptions are horizontally aligned. For that purpose we’re defining a main grid of 3 columns, and a subgrid for each product with the 3 rows.
As we can see even if the title has 2 lines, or independently of the lines in the description, the items are properly aligned.
This cannot be achieved with
because of it’ll add all the products in a single row
(actually 3 rows in the grid).
Because we’re setting the row explicitly to
<h1> (row 2),
<img> (row 1) and
<p> (row 3) elements.
Without subgrids, those rows cannot be automatically translated
to rows 5, 4 and 6,
when the products have filled the 3 columns defined on the main grid.
We’ve been reading the spec and found some potential issues thinking about how to implement subgrids. These are some of them in no specific order.
Margin, border and padding
Probably the most important issue is the problem with margin, border and padding on the subgrid. And how they affect to the grid track sizing algorithm.
Let’s try to use a simple example to explain it, imagine a 3x2 grid where we’ve a subgrid taking the first row completely.
Imagine that each item’s width is 100px, so the columns will be 100px width each one.
However, if we set for example the padding on the subgrid (e.g.
padding: 0px 50px;),
we’ll have to do some extra operations to calculate the size of the tracks:
- First column, as it’s on the left edge of the subgrid we’ll be adding 50px to the size computation. Resulting on a 150px track.
- Second column is not affected by the padding, so it keeps being 100px.
- Third column, is in a similar situation than the first one because it’s on the right edge of the subgrid. So the final size is 150px.
The problem here is that the grid track sizing algorithm works directly with the grid items. So it’d need to know if the item is in one of the edges of the subgrid in order to use the margin, border and/or padding to compute the size of the track.
On a first sight this might seem doable,
but if we think on items spanning several tracks and nested subgrids
things become really complex.
For example, imagine that we’ve a nested subgrid that takes 2nd and 3rd columns
on the first row with
padding: 0px 25px;.
For each column of the main grid container, we’d need to take into account the different paddings of the subgrids. So for each item we’d need to know not only if it’s on the edge of the subgrid but also check the ancestors.
On a related note, having scrollbars on the subgrids have similar issues related to track sizing.
Implicit tracks on the subgrid
The issue here is what happens when we get rid of explicit tracks on the subgrid. According to the spec, the items in this situation should use implicit tracks of the subgrid, and not take tracks from the main grid. Which means that they’re not aligned with the main grid (they don’t share lines with it).
Let’s use an example to illustrate this issue:
As we can see the subgrid items
si4 are placed in implicit tracks
of the subgrid. Those tracks has no relation with the main grid container,
literally from the spec: “they effectively extend in a third dimension”.
We cannot think in a use case for this particular topic,
and it seems really weird as the main goal of the subgrid is to share the lines
with the main grid container.
Besides, imagine a different example of an auto-sized column, and some items from a subgrid in that column that span in and out the explicit subgrid. It’d be really complex from the grid track sizing algorithm point of view, to determine the size of that auto-sized column of the main grid container.
Automatic grid span
In the previous examples we were defining subgrids explicitly setting both the grid position (the initial column and row for the subgrid) and the grid span (how many cells the subgrid takes in each direction).
However, we can define a subgrid just setting the grid position with an automatic grid span. According to the spec, the implicit tracks on the subgrid will determine the span.
Again hopefully one example can help to get the idea:
The subgrid’s grid position is set to the 2nd column and the 1st row.
Then the first 2 items (
si2) are placed in the tracks
from the main grid (2nd and 3rd column respectively).
But the last item (
si3) get rid of tracks,
so it’s added on an extra implicit track on the subgrid
unrelated to the main grid container.
Because the subgrid doesn’t create implicit tracks on the main grid,
This seems quite complex to manage, specially if the subgrid cannot create implicit tracks on the main grid container. Also, if we combine it with auto-placement (so we don’t set the grid position), finding the right position and span might be tricky.
On top of that, imagine that one of the items in the subgrid
is positioned using
As the subgrid doesn’t have a grid span yet,
probably it’d be placed on the first column of the subgrid,
when we’d be expecting it to be on the last one.
Subgrid only in one axis
subgrid keyword can be set in both properties defining the grid
grid-template-rows) or only in one of them.
If we set it only in one of them, we’re creating a subgrid only in one direction.
Let’s see one example:
In this case we’re defining a subgrid only for the columns direction, so in order to calculate the size of the items in the 1st and 2nd columns it use the track sizes defined in the main grid container.
However, for the rows we’re not setting anything, so it uses auto-sized rows. This means that the rows will behave like in a regular nested grid, completely independent of the parent grid container.
Probably this is feasible to implement, but again it seems a weird feature, we might need some good use cases to decide about it.
Another issue with subgrids is that we can nest them as much as we want. So, in order to determine the size of a track in the grid container, we need to traverse not only the direct children, but also all the descendants. This can have a huge performance impact if nested subgrids are abused.
Regarding this point, probably we’ve to simply live with it and navigate all the descendants being aware of the performance penalty.
Probably grid gaps properties should be ignored in the subgrids. We want the items to be aligned with the main grid container, so having different gaps seems really strange.
This is not in the spec, but we guess that the reason is that grid gaps were added after subgrids, so that part of the spec was not updated.
There are other things that we didn’t explore in detail. For example:
- Named grid lines from the main grid container used in the subgrids.
- Positioned items in the subgrids.
- Subgrids with orthogonal flows.
And we’re sure there are more things that we’re missing at this moment.
As we can see there are a bunch of potential issues, of course they need a deeper analysis and further discussions, but the complexity of the whole feature seems not small at all.
We’ve been thinking in another idea, trying to fulfill the use cases described previously in this post, and avoid the issues as much as possible. This is a pre-alpha proposal, so take it with a grain of salt.
The ideas would be to have a limited support of subgrids:
Make the subgrid pretty similar to
display: contents;, so we cannot set margin, border or padding on it. That will simplify the calculations needed to determine the size of the tracks and the items.
Main difference with
display: contents;is that the subgrid will allow to translate positions depending on the final placement on the main grid container. Like in the use case of the shop catalog.
Remove implicit tracks on the subgrid, so we need to always set a grid span (how many columns and rows the subgrid takes) beforehand.
Items trying to be placed on the implicit grid of the subgrid, would end up on the first cell of the subgrid. For items spanning outside the explicit grid, the span would be truncated at the end edge of the subgrid.
It seems clear that items in the subgrids need to be positioned before the items in the main grid container. And once all the positions are resolved, we could try to run the grid track sizing algorithm as usual.
Probably on an initial approach only allowing subgrids in both axis might be enough.
With this proposal the use cases explained in the first section would be covered, we’d need to be more specific on the CSS, but they’ll work.
We’d lack the chance to set CSS properties on the subgrid itself, but we could add an extra item on the subgrid that spans the whole subrid and paint a border, background or whatever is needed. Not an ideal solution anyway.
This post is mostly a braindump from the Igalia team working on CSS Grid Layout, after one day discussing about this part of the spec. We just want to share it with the rest of the web community, the CSS WG and anyone interested on the topic. In order to help to move forward the decision regarding what do to with subgrids in the CSS Grid Layout specification.
Lots of questions about subgrids are still hanging in the air:
- Defer them to level 2?
- Simplify them and keep them on level 1?
- Keep them as they are and wait for subgrids before shipping CSS Grid Layout?
We think there aren’t good answers to these questions right now, hopefully we all together will find the right solution and find a final solution that makes happy all the involved parties. 😄
Last but not least, there’s going to be a CSS Grid Layout Workshop in New York City by the end of the month organized by one of the spec editors (fantasai). My colleague Sergio, who is the maintainer of Grid Layout code in Blink and WebKit will be participating in this event. Hopefully this and other topics will be clarified there, and the specification could move to Last Call Working Draft (LCWD) towards Candidate Recommendation (CR)!
- Russian (February 18, 2016): Мысли вслух о подсетках в CSS Grid Layout