Building a CSS Grid Overlay

Avatar of Andreas Larsen
Andreas Larsen on

Let’s take a look at what it takes to build a grid overlay with CSS. It will be responsive, easily customizable and make heavy use of CSS variables (known more accurately as “CSS custom properties”). If you aren’t familiar with custom properties, I’d highly recommend reading What is the difference between CSS variables and preprocessor variables? and watching Lea Verou’s enlighting talk on using them.

This grid overlay that we’re building will consider a developer tool, as in, a tool just for us, not really our users. So, let’s not worry too much about browser support (If you do care, check out caniuse… data on custom properties). While it’s impossible to preprocess custom properties to behave exactly the same as native support, if you use them just like you would preprocessor variables, tools like the postCSS plugin cssnext can transform them into CSS compliant with older browsers.


A couple of weeks ago, at work, I simplified the media queries on one of our projects and added a layout component based on the same principles as Flexbox Grid. Some of my fellow designers didn’t fully understand the responsiveness and fluidity of it, so I created a toggleable grid overlay to help them visualize it.

My hope is that this can be a tool to aid layout-related conversations on our teams and make sure we don’t use too many bespoke widths, paddings etc.


Working as a front end designer I want all developers and designers to speak the same language (as much as possible) so I’ve chosen a terminology for the CSS variables that digital designers are also familiar with:

  • Columns: The vertical divisions of the page.
  • Gutter: The space between the columns.
  • Offset: The space between the sides of the viewport.
  • Baseline: The vertical rhythm used for text.

Making the Grid

1) “Box”

Let’s use a pseudo-element on the element to display the grid on top of all of our content. We want the overlay to work with a fluid layout, so we give the element a width off `100% – (2 * offset)` and also a max-width so the grid overlay doesn’t grow wider than our layout.

See the Pen

2) Columns

If you look at the grid you will notice that the repeating pattern is column+gutter pairs. We’re using repeating linear gradients as a background-image. We’ll set the size of the background-image to 100% + gutter making the repeating pattern 100% / columns wide and the actual column (100% / columns) – gutter wide.

See the Pen

As a side note, I also tried using regular linear gradients with background-repeat to get the lines more pixel perfect. It didn’t work because pixel rounding resulted in imperfect total width whenever the layout width wasn’t dividable by the number of columns.

3) Baseline

We also draw the baseline using repeating linear gradients but it’s slightly simpler since we don’t add horizontal gutters and we want it to be just a line instead of a block.

Let’s also add a baseline-shift variable that allows us to shift the baseline slightly upwards or downwards. We apply the baseline shift by simply adjusting the background-position.

See the Pen

4) Media Queries

Now that we have our basic setup, let’s introduce some media queries. If you look back at the math that we’ve used so far, you can see that none of it is tied up to any specific number of columns, gutter width, etc.

We use a mobile first approach and only include variables in the media queries when we want to change them. To make it clear for everyone using the overlay that we’ve passed a new breakpoint we also change the color at every breakpoint.

I recommend opening the Pen in a new tab and see how it behaves when you change different variable values and when you resize the viewport.

See the Pen

If you made a mental note in step 1 saying “but what if I want specific layout widths at specific breakpoints?” then now is when you can easily introduce that logic by setting --max_width for each media query.

5) Help Text

Designers like to think about mockups for different devices — which is generally a good thing as it’s critical that a website looks awesome on those different devices — but sometimes they forget that the layout on an iPad should work all the way up and/or down to the next breakpoint.

Breakpoints aren’t normally called “iPhone”, “Galaxy Note 🔥”, “iPad” etc. for many reasons including the above. A breakpoint denotes where a new range starts and it’s not device specific.

To make it more obvious what our breakpoints are called, we can add the names to our grid overlay.

See the Pen

I have a dream that one day a designer doesn’t come back to a developer and say: “we need to adjust how it looks on iPad” but instead says “we need to adjust how it looks on medium”.

Go Further

What about lines for the columns and gutters too? Easy, it’s just CSS. What about adding more breakpoints? Easy, it’s just CSS. What if I want different colors? Easy… you get it. 😄

You can see a more advanced example here:

See the Pen

I’d love to get your input either here or on the GitHub repository which also includes a Chrome extension using this approach.