The Dark Side of the Grid (Part 1)

posted on

CSS Grid Layout is one of the most exciting recent CSS specifications because of its flexibility, extent, and power. It makes our lives so much easier but it also creates new dangers regarding user experience and accessibility.

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

  1. What’s CSS Grid Layout? (in this article)
  2. Name and theme of this article (in this article)
  3. Pink Floyd Fun Fact 1 (in this article)
  4. Compromising on Semantics (in this article)
  5. Pink Floyd Fun Fact 2 (in part 2)
  6. Changing Visual Order (in part 2)
  7. Cross Browser Support
  8. Pink Floyd Fun Fact 3
  9. Whose responsibility is it?
  10. 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.

If you are adding widths to all your flex items, you probably need grid.

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.

The “The Dark Side of the Moon LP” in front of some of my other records.
I found this LP in a record store in Warsaw after talking about the dark side of the grid at Frontend Con 2018.

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 believe there will be a strong temptation, especially with Grid, to flatten out document structure in order that all elements become a child of the element with the Grid declared.
Making layout simple, but at what cost?

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:

The headings spans the whole with and the list items are split in 3 columns

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 lis for divs 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.

Browsersupport table on caniuse.com for subgrids.
At the moment, subgrids aren’t a standard yet and not supported in any browser.

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.

Browsersupport table on caniuse.com for display: contents; Supported by alt major desktop browsers but only in Firefox without bugs.
Edge doesn’t support display: contents due to an accessibility bug in Chrome, Safari and Opera.

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.

The accessibility panel in Chrome DevTools.
The ul should have a role of list but inspecting the element shows that it's not exposed to the accessibility tree at all.

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.

Thank you to Aaron and Max for reviewing this article.

Resources