Preface
It has already been two years since the first browsers, Chromium 57 and Firefox 52, shipped CSS Grid Layout un-prefixed. Many developers have experimented with it or are using it in production already. More will come as soon as support for Internet Explorer 10 and 11 becomes less important.\
Grid offers many ways of building layouts and it challenges us to rethink the way we approach them. This flexibility is great for our development experience, but it may come at the cost of user experience and accessibility if we don’t use it responsibly.
This series of articles will give you an overview of potential implementation pitfalls, or in other words, the dark side of the grid.
Overview
- What’s CSS Grid Layout? (in this article)
- Name and theme of this article (in this article)
- Pink Floyd Fun Fact 1 (in this article)
- Compromising on Semantics (in this article)
- Pink Floyd Fun Fact 2 (in part 2)
- Changing Visual Order (in part 2)
- Cross Browser Support
- Pink Floyd Fun Fact 3
- Whose responsibility is it?
- Pink Floyd Fun Fact 4
What’s CSS Grid Layout?
CSS Grid Layout is a grid-based layout system designed for two-dimensional layouts. It’s the first true layout method in CSS. Properties like float
, display: inline-block
, position
, and display: table
were not originally intended for building layouts.\
Grid is a great choice if you're not working on just one axis but one two axes.
Of course, there’s Flexbox, but its strength lies in distributing available space and placing items either vertically or horizontally. Flexbox loses a lot of its flexibility as soon as you’re applying flex-wrap
and add widths to your flex items.
This article assumes that you have at least a basic knowledge of CSS Grid Layout. If you're new to the topic, I suggest you check out gridbyexample by Rachel Andrew or Grid Garden before you continue reading.
Name and theme of this article
Before we dive into the dark side of the grid, I wanted to quickly address the name and theme of this article. They’re based on the LP The Dark Side of the Moon by Pink Floyd, released in 1973.
Now you might think I’m a huge Pink Floyd fan. Well, I’m sorry to disappoint you, I’m not, I just like the design. However, I can’t borrow their design without telling you about them.
Therefore, I present to you: Pink Floyd Fact #1.
Pink Floyd Fun Fact #1
The Dark Side of the Moon is, with over 45 million copies sold, the fourth best-selling album worldwide. Only Back in Black by AC/DC (50 Million), Their Greatest Hits (1971–1975) by The Eagles (51 Million) and, of course, Thriller by Michael Jackson (66 Million) have sold more often.
Compromising on Semantics
Even before grid shipped in any browser, experts like Rachel Andrew were already fearful that developers would compromise on semantics and flatten out document structures to use CSS Grid.
I’ll show you why in a simple example (I know that there are different solutions for this particular task but this is just a demo to illustrate the issue).\
\
Let’s say we have a section
with a heading and a list of items.
<section>
<h2>Pink Floyd discography</h2>
<ul>
<li>The Piper at the Gates of Dawn</li>
<li>A Saucerful of Secrets</li>
<li>More</li>
<li>Ummagumma</li>
<li>Atom Heart Mother</li>
<li>Meddle</li>
<li>Obscured by Clouds</li>
<li>The Dark Side of the Moon</li>
</ul>
</section>
The section
forms a 3-column grid, we want the heading to span all columns, and each li
should fill one cell.
It should look something like this:
That shouldn't be too hard. We select the section
, set display: grid
, add 3 even columns, a 10px
gutter and we make the heading span all 3 columns.
section {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
}
h2 {
grid-column: 1 / -1;
}
And this is what we get:
See the Pen QYgjZe by Manuel Matuzovic (@matuzo) on CodePen.
Doesn’t exactly look as expected. The thing is, only direct children of the grid container will align with the grid. In our example, those are the h2
and the ul
– but we want all the li
elements to fill cells in the grid.
Okay, let’s try to fix that.
PS: I'm well aware that I could apply display: grid
to the ul
directly but this is just a simplified example. There are other (more complicated) use cases where you can’t do that easily.
Solution #1: Flattening the document structure.
If the placement algorithm only affects direct child elements, we’ll just make our li
direct children by removing the ul
and swapping the li
s for div
s to avoid invalid HTML. This is a solution, but it’s a bad solution because we’re compromising on semantics for design reasons.
<section>
<h2>Pink Floyd discography</h2>
<div>The Piper at the Gates of Dawn</div>
<div>A Saucerful of Secrets</div>
<div>More</div>
<div>Ummagumma</div>
<div>Atom Heart Mother</div>
<div>Meddle</div>
<div>Obscured by Clouds</div>
<div>The Dark Side of the Moon</div>
</section>
Flattening the document structure may have bad effects on the semantics of your document, which is especially bad for screen reader users. For example, when you’re using a list, screen readers usually announce the number of list items which helps with navigation and overview.\
Also, a flat document might be harder to read when displayed without CSS.
Wait! What? Why would someone disable CSS?
It’s unlikely that users disable CSS on purpose but sometimes an error occurs or the connection is just so slow that only the HTML displays successfully. If you’ve ever been on vacation in Italy and had to use public WIFI, you know what I’m talking about.
Please don’t flatten document structures.
Solution #2: Creating a subgrid
The arguably best solution would be to use subgrids. A grid item can itself be a grid container with its own column and row definitions. It can also be a grid container but defer the definitions of rows and columns to its parent grid container.
ul {
display: grid;
grid-template-columns: subgrid;
}
By setting the value of grid-template-columns
to subgrid
on the unordered list, the list items now align with the parent grid. This is super cool!
Unfortunately, support for subgrid is so bad, it doesn’t even have a caniuse page. Subgrids are part of level 2 of the CSS Grid Layout specification which is still a working draft.
Use subgrids as soon as they’re available.
Solution #3: Using display: contents
An alternative to using subgrids is a different property that has a similar effect. If you set the display
value of an element to contents
, it will act as if it got replaced by its child items.
ul {
display: contents;
}
In our example, this causes the list items to take part in the alignment of the sections grid because for them the parent ul
doesn’t exist anymore. This is exactly what we want, and it works perfectly fine but, (yeah I’m sorry, there’s a but) Edge doesn’t support it.
The lack of support per se isn’t the issue but rather why it’s not supported. There’s a bug in Chrome, Opera, and Safari that removes an element with a display
value of contents
from the accessibility tree, making it inaccessible to screen reader users. It’s like applying display: none
– the element just doesn’t exist anymore for assistive technology.
Microsoft Edge will consider adding the feature as soon as blink and webkit-based browsers fix the bug. Consider not using contents
until then.
Solution #4: Nesting grids
As already mentioned, a grid item can also be a grid container. We can select the unordered list, make it span the whole width, and inherit values from the parent grid.
ul {
grid-column: 1 / -1;
display: inherit;
grid-template-columns: inherit;
grid-gap: inherit;
}
Nesting grids isn’t a perfect solution and sometimes it might not work, but in this simple example it’s good enough.
See the Pen Grid nesting issue solution by Manuel Matuzovic (@matuzo) on CodePen.
Recap
The situation regarding subgrids is anything but perfect. The subgrid
value isn’t a standard yet, display: contents
is buggy, and nesting grids will only work in specific use cases. If you see yourself compromising on semantics just to use CSS Grid Layout, don’t use it or try to workaround the problem until browsers fix the display: contents
bug or ship subgrids.
This was part 1 of the dark side of the grid. In part two I’ll show you how easy it is to confuse users unintentionally, why it’s bad, and how to avoid it.