After battle-hardening Flexbox and learning all the deets at my previous gig, the last 6 or so months I've focussed on learning the ins-'n-outs of CSS Grid. Turns out the experts were right; CSS Grid is astonishing! It's become my 🍞 bread and 🧈 butter for building anything, save for a couple of unique cases where Flexbox makes more sense1.

Today I want to focus on a concept I've been thinking about for a while; using a feature of CSS Grid to improve website accessibility for people with disabilities. Let's set the stage and build a website!

<div> it up

We're going to build a wireframe-like website to be able to explain the concept. Let's visualize a small content site, nothing fancy. Altogether; a header and an area for the main content. For the sake of this example, the header has 2 article links, too.

Something like:

Image of an example vertical layout, with a header on top and a main content area in the middle / bottom. It doesn't look very professional...

Perfect! The mark-up for such a site is as you would expect it:

<!doctype html>
<html>
    <head>
        <!-- Everything in the head, omitted for simplicity -->
    </head>
    <body>
        <div class="app">
            <div class="app__header"></div>
            <div class="app__main"></div>
        </div>
    </body>
</html>

This could probably be more semantic HTML-wise, but that's not the point of this blog. Please bear with me 😉 One of these days I'll find a cure for my <div>itis…

Now what's fun is that even before CSS grid was mainstream, we wouldn't need a lot of styling to achieve our sought after layout. Since <div>'s are display: block by default, they should stack vertically as per the design. All that we need to complete our design is some margin, padding & coloring. Something along the lines of:

.app__header {
    background-color: #6b21a8;
    color: #fff;
    margin-bottom: 30px;
    padding: 30px;
}

.app__main {
    background-color: #9a3412;
    color: #fff;
    margin-bottom: 30px;
    padding: 30px;
}

Hey Jochem, 2010 called and it wants it's styling back! Alright alright, settle down ✋😌🤚 let's talk CSS Grid!

Gettin' Griddy wit It

I'm going to focus on the concept of named lines in CSS Grid. They're one of the countless ways CSS Grid can be used. After experimenting lots I've found it to be the most explicit way to define grids. It's kind of like how my mind works?

Similar to my mind; named lines are pretty strange. At first, you're like "Whaaa? That's CSS!?" Let's dive in.

Multi Dimensional CSS

As you might know, properties like margin and padding are pretty one-dimensional in a sense that you enter a value and can expect CSS to produce the desired result:

property: /* result */;

A classic "one-two", or, as we call it here in The Netherlands: een "een-tweetje".

This is a thing I love about CSS. Boom. Ya got padding. Boom. Added margin. Boom. Background-color to make it look spiffy. It has a certain rhythm to it 🎶

background-color: /* result */;
margin: /* result */;
overflow: /* result */;
padding: /* result */;
z-index: /* result */;

/* and so on */

Named lines are similar, but—quite literally—add an extra dimension. You can keep adding information in the result part as needed. It requires visualizing a layout in one direction in your head, and for you to think about "what comes next". Let me explain:

Named lines

CSS Grid has a property called grid-template-rows that allows you to define rows in the vertical direction2. Let's apply this property to our example layout. We start with adding the following:

.app {
    display: grid;
}

This activates CSS Grid on our parent and allows us to use all the options. Next, let's examine the example layout vertically. This is the visualizing part I mentioned earlier. What do we see in our design, in order, going from top to bottom?

  1. The header
  2. The content

And kapow! You've written your first grid-template-rows declaration 💪 all you need to make it work, is to learn how to transform this to something CSS Grid understands. Let's examine how you can write a named line declaration:

Description of a named line. There's an opening square-bracket, a custom string, a hyphen to indicate the end of the custom string, either start or end and a closing square-bracket.

Cool! The first string in a named line declaration is a customizable one. It's entirely up to you what you enter, be it header, bottom, chewbacca or cool-summer-breeze. Go nuts! You can even add multiple hyphens (like in the cool-summer-breeze example)! The only thing you need to remember hyphen-wise is that the hyphen before start or end gets to be the one that signals: "Custom string done!"

Speaking of start and end, the second part is either of those 2 options. Both strings let the parser know whether it should begin (start) or complete (end) the lay-outing for this particular row. Wrap the entire string in [ square brackets ] and you're off to the races 🐎

What typically follows in a named line declaration is a <unit-of-measurement>. This can be in px, em, rem, whatever! There's even the fractal unit fr and the keyword auto which are magical. The specifics of these units warrant an entire new post, explaining the ✨ magic ✨ you can achieve with 'em.

One extra thing you need to know, is that you can add multiple row namespaces in one named line declaration. You can start and stop rows at the same point on the grid:

/* ... */ [header-end main-start] /* ... */

Let's write the final grid-template-rows declaration for our example, using what we've explored:

.app {
    display: grid;
    grid-template-rows: [header-start] 300px [header-end main-start] 600px [main-end];
}

(If you're on a small screen, you'll probably need to scroll right here to see the full declaration →)

See where we lost the one-dimension CSS normally has here? Pretty exciting right? All that's left, is to make sure our individual child elements in the .app parent listen to these instructions. We do that like so:

.app__header {
    /* Properties from earlier, see above */
    grid-row: header;
}

.app__main {
    /* Properties from earlier, see above */
    grid-row: main;
}

That should do it! Boom. You're awesome. I'm awesome. We're all awesome! Take a break, get a sparkling water, bask in the glory of your genius.

When you're fully hydrated & ready, we'll explore how this concept applies to accessibility.

Accessibility mind-games

To fully grasp on how this concept helps us make sites more accessible, we first have to do a little thought experiment. Let's imagine how 2 users would use this site:

User 1

The first user, not impaired eyesight-wise, navigates the site using the eyes. What the user sees is how our site gets interpreted. When User 1 visits the site, they likely interpret the site according to the earlier element order I used to explain our CSS Grid named line declaration. To reiterate, that was this order:

  1. The header
  2. The content

User 1 first sees the header, followed by the content after that. Now imagine they read the first article and move to a second page. Since they've scanned the page layout in the first article, they instinctively "know" that they can ignore the header and instantly focus their eyes on the content area to start reading the second article.

Cool! All we need to know about User 1. Let's move on to our second user.

User 2

The second user has an eyesight impairment, making it impossible to use the site visually. Amazingly, we live in a time where devices exist to help these users browse our site. Such a device is commonly referred to as a "screen reader". It scans the website and reads back everything it finds enabling the user to navigate.

A similar experience for users without such a device is trying to use a site solely with ⇥ Tab. A ⇥ Tab press jumps to the next identifiable anchor on the page. A ⇧ Shift + ⇥ Tab press goes in the opposite direction. Using this knowledge, let's examine how this second user uses our site.

Coming in fresh, they start at the header. They jump through the article links in the top right, moving on to the content. After reading the entire article they're probably a fan and they also want to get to the second article right? Now they have to reverse all the way through the article, back to the header at the top to find the next page. Okay, that was a chore...

Next, User 2 clicks on the second article link. The page refreshes and focusses the first identifiable anchor on the page. Which is, as per our layout, the header! The second user now has to navigate our entire header again to get to the content they wanted. Pretty maddening, I can imagine!

Solutions

Fortunately, nowadays there are countless solutions for these problems and a lot of web developers are willing to stress these details allowing all users fast access to websites. ❤️

For example, my fellow Dutchies over at De Voorhoede wrote a great post about how we can use a "skip-link" to allow users to skip to the main content on the page.

Coming back to the concept I've been thinking about however, I hypothesize we can now use CSS Grid to fix these problems.

Fixing accessibility with CSS Grid!

Okay, time to use what we've learned CSS Grid-wise and fix the issue we have in our example site for User 2! First, let's summarize where we're at, code-wise. Our mark-up is as follows:

<!doctype html>
<html>
    <head>
        <!-- Everything in the head, omitted for simplicity -->
    </head>
    <body>
        <div class="app">
            <div class="app__header"></div>
            <div class="app__main"></div>
        </div>
    </body>
</html>

And our CSS is the following:

.app {
    display: grid;
    grid-template-rows: [header-start] 300px [header-end main-start] 600px [main-end];
}

.app__header {
    background-color: #6b21a8;
    color: #fff;
    grid-row: header;
    margin-bottom: 30px;
    padding: 30px;
}

.app__main {
    background-color: #a3a3a3;
    color: #fff;
    grid-row: main;
    margin-bottom: 30px;
    padding: 30px;
}

Awesome! Let's think about how we can fix the issue of User 2. The problem is, to reiterate:

User 2 has to navigate through the entire header to get to the main content of the page.

Okay, so wouldn't it make sense to move the main content of the page upward in the DOM, before the header even, so the first focusable element is something inside the main content? Let's try!

<!doctype html>
<html>
    <head>
        <!-- Everything in the head, omitted for simplicity -->
    </head>
    <body>
        <div class="app">
            <div class="app__main"></div> ⬆️ <!-- Move over! -->
            <div class="app__header"></div> ⬇️ <!-- HEY! No skipping in line jerk! -->
        </div>
    </body>
</html>

Now when User 2 presses ⇥ Tab after freshly navigating to a new page, the first element focussed should be inside the main content, instead of the header.

But wait a minute, doesn't the page suddenly look weird for User 1? The header is now in the middle of the page and the content is at the top and that's so wro...

Let me stop you there. Or better yet, let CSS Grid stop you there 🧘

Conclusion & experimentation

To encourage experimentation, please take a moment to reproduce this in a tool like Codepen !

After reproducing our small use-case based on the above code, you probably noticed that the layout didn't change visually. This is because we've overridden the DOM layout with CSS Grid and our named lines, preserving the layout visually for User 1.

CSS Grid, now overruling the DOM order, is dictating where child elements go vertically. We should get exactly what we got when we first started:

Image of the exact same example vertical layout, with the visual order intact. Header on top, main content on the bottom!

Except User 2 is now able to immediately start ⇥ Tab'ing in the main content. The CSS Grid named lines ✨ magic ✨ freed up the DOM order for us to do cool thingamajigs that improve accessibility for User 2.

We've fixed the issue and now have two incredibly happy users. Great job, high-fives all around! 🙏

Debate club!

Now I know what you're thinking:

"Is this a good idea?"

And to be honest, I don't know. All I know is: I find it cool we now have techniques like these that make it possible to help users who would otherwise have a harder time using the web. Thinking about new ways to put these modern front-end techniques to use helping make sites more inclusive and faster for everyone is like... the best thing ever 🥳

What do you think? Do you agree or disagree? I look forward to hearing more opinions in this space, so please send any thoughts via a tweet @jochemkeller or drop a notice via my contact page!


  1. Ahmad Shadeed has a thorough post about when to use Flexbox vs. CSS Grid. Give it a read if you haven't already!
  2. I know there's a lot of if's and butts to this statement and that there are multiple similar statements in this post. CSS Grid isn't as one-dimensional as I make it out to be. I'm aware of it, and so should the user. Hopefully this footnote adequately clarifies that. My goal for this post was to focus more on my thought experiment than the technical implementation. Thusly, for simplicity's sake, I tried to make it as straightforward as possible. I hope you understand 😌