CSS Grid Layout with Responsive Breakpoints

8 Sep 2020

Here's an easy way to build responsive layouts with a new-ish CSS feature (circa ~2017). It combines two techniques—CSS Grid + SCSS breakpoint mixins—in a way I hadn't seen in other tutorials/StackOverflow threads.

This is an alternative approach to older layout methods that depend on floats, flexbox, and tables. Mastering display: grid and taming @media queries can help free you from frameworks like Bootstrap, Tailwind, etc. You can write lightweight, maintainable CSS from scratch instead!

Here's what we'll make:

A simple layout that changes at a single breakpoint. It's easy to add more breakpoints and related CSS rules.

Table of Contents - CSS Grid Layout with Responsive Breakpoints

  1. Toolset
  2. HTML
  3. Responsive Breakpoints
  4. Grid Layout

A. Toolset

We'll combine CSS Grid Layout —supported by all major browsers beginning in 2017—with SCSS mixins to create a responsive layout.

Our goal here is a barebones starting point with as little code as possible. Basically, this is a scaffold for tinkering with CSS Grid in a useful context 1.

The following examples are written in Slim and SCSS. I explain most of the code with inline comments. These code samples are from a skeletal Rails app (repo here) but you don't need to understand Rails to follow along. File paths are relative to the app's root directory.

B. HTML

Here's the HTML (Slim) 2:

app/views/layouts/application.html.slim

Our stylesheet_link_tag (👆 line 8) imports two SCSS files:

app/assets/stylesheets/application.scss

The line order is important. We import breakpoints.scss first so we can call its mixins.

C. Responsive Breakpoints

breakpoints.scss does two things:

  1. Defines breakpoints, and
  2. Defines 3 SCSS mixins for interacting with the breakpoints elsewhere in our CSS:

Here is a heavily-commented version of breakpoints.scss (uncommented version here):

app/assets/stylesheets/breakpoints.scss

D. Grid Layout

Now we'll use CSS Grid to create a simple nested grid layout. I'll explain what we're doing before jumping into the code.

First we set up a grid on .page-grid. This grid has three (3) rows and one (1) column. The .sidebar and .main divs default to display: block and are therefore stacked. In other words, we're developing "mobile first."

Then, when window width exceeds 640px, our mixin applies a subgrid to #content. The .sidebar and .main divs sit side-by-side in the subgrid row at least 600px high. .sidebar has a grey background.

To be clear, display: grid is not really necessary for .page-grid in our example. I went with display: grid to make it easier to extend the layout later 3.

Below is a heavily-commented version of index.scss (uncommented version here):

app/assets/stylesheets/index.scss

Extending this grid from here is easy. Use respond-below(screen) and respond-above(screen) to apply breakpoint-specific CSS rules. You could also define additional breakpoints in breakpoints.scss and call respond-between($lower, $upper) to apply rules to ranges.

I hope you find this template and walk-through useful. Happy layout designing!

1 If you're looking for deeper coverage, I strongly recommend Rachel Andrew's Get Ready for CSS Grid Layout, which details all of CSS Grid Layout's features and specifications.
2 In a conventional Rails app, this code would normally span two separate files: app/views/layouts/application.html.slim and app/views/pages/index.html.slim. I've consolidated into one file for simplicity.
3 I've been debating when it's best to default to display: grid for layout elements in a design.