---
title: Concise Media Queries with CSS Grid
teaser: 'Write less CSS and organize responsive layouts with ease.

  '
tags: css,design
author: Stephen Lindberg
published_on: 2018-10-26
---

![abstract illustration of grid layout](https://images.thoughtbot.com/blog-vellum-image-uploads/Lf3CIKbRRQ2iuN5OaEJr_header.png)

Media queries are commonly used to control responsive layouts on websites.
Organizing layouts this way is intuitive: On a wide desktop display, we want to
present information in columns, and as screen width diminishes below a
threshold, we stack elements vertically. With modern CSS, solutions to this
problem have become easier than in the past. No longer must we use kludgey rules
like `display: table;` to achieve the layout of our dreams. CSS modules like
flexbox and several clever frameworks have made grids easy to achieve with
minimal code, but with CSS grid we can write our grid rules once, and achieve
the desired layout at any screen size with a single rule, and without any
framework.

As an example, let's take a common layout for a user profile. In a profile we
have a user name, avatar, and short biography. Our markup might look something
like this:

```html
<div class="user-profile">

  <span class="user-profile__username">
    Rob Ott
  </span>

  <img src="avatar.jpg" class="user-profile__avatar"/>

  <p class="user-profile__bio">
    made of metal
    likes animals
    hates water skiing
  </p>

</div>
```

### How do we flex it?

I've seen media queries of all varieties trying to solve the same problem. A
common method is to describe a media query which sets the rule `display: flex;`
on a container above a certain width:

```css
@media (min-width: 700px) {
  .user-profile {
    display: flex;
    ...
  }
}
```

This relies on the initial `flex-direction` of a flexbox being `row` and the
initial value of `flex-wrap` being `nowrap`. When the children are block
elements, they will naturally stack vertically when the `display: flex;` rule no
longer applies. Alternatively, we could write a query to swap the value of
`flex-direction` for `row` or `column`.

The drawback to the flexbox solution is that in order to achieve complex layout
rules with blocks arranged along 2 axes, such as an element spanning 2 rows, we
must:

1. nest elements
2. write queries to ensure margins and gutters (white space between rows and
   columns) remain equal,
3. trip over the `order` rules of child elements to correctly organize them.

What a headache! Media queries will quickly get out of hand if we take this
approach for any complex layout.

### Enter grid-template-areas

CSS grid definitely has the advantage when it comes to quickly organizing
layouts. Even simple layouts require minimal effort with CSS grid compared to
flexbox. With the `grid-template-areas` property, we can write responsive
layouts with a _single rule_ inside a media query. That's because
`grid-template-areas` defines a visual grid system on both axes at the once.
Take a look:

```css
.grid {
  grid-template-areas:
    'avatar name'
    'bio    bio';
}
```

This rule tells the container that there are three areas: "name", "avatar", and
"bio", arranged in a pattern with the avatar and username side by side in the
first row, and the bio section in a second row spanning both columns. The magic
of this rule is that the number of columns is inferred by the property values.
Each name separated by one or more spaces defines a column (and each row must
define the same number of columns). For clarity, I broke up the rows onto
separate lines to visualize the result of the grid. Our child elements simply
need to tell the grid which area they appear in, and the container does the
rest:

```css
.user-profile__username {
  grid-area: name;
}

.user-profile__avatar {
  grid-area: avatar;
}

.user-profile__bio {
  grid-area: bio;
}
```

![illustration of profile grid layout](https://images.thoughtbot.com/blog-vellum-image-uploads/9STxIBHfQpydOPOaxS2o_grid.png)

Now a simple media query to rearrange the grid template will handle our
responsive layout:

```css
@media (max-width: 700px) {
  .grid {
    grid-template-areas:
      'name'
      'avatar'
      'bio';
  }
}
```

![illustration of stacked layout with name on top](https://images.thoughtbot.com/blog-vellum-image-uploads/A72iuTnRaqIk9bhhHNDZ_stack1.png)

And now our children will stack vertically in a viewport up to 700px!

### Keep accessibility in mind when reordering elements

When reordering elements visually, it's important to ensure that the document
structure is ordered logically for accessibility. [Here][accessibility for grid]
are some thoughts on maintaining accessibility when working with grid.

Now, what if we want to show the user's avatar first, with their name
underneath? we can simply reorder the areas with the same property:

```css
@media (max-width: 700px) {
  .grid {
    grid-template-areas:
      'avatar'
      'name'
      'bio';
  }
}
```

![illustration of stacked layout with avatar on top](https://images.thoughtbot.com/blog-vellum-image-uploads/coRQ4iZ5QSajdHDJn5bY_stack2.png)

Furthermore, we can rearrange the grid areas in any arbitrary layout with that
single rule, and because the CSS grid system handles [gutters][gutters] with a
flick of the `grid-gap` rule, we don't have to worry about any conditional
margins on our child elements. So the next time you tackle a layout with complex
responsive behavior, choose CSS grid and spend less time in front of your
computer.

[accessibility for grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/CSS_Grid_Layout_and_Accessibility#How_should_we_approach_accessibility_for_grid_layout
[gutters]: https://developer.mozilla.org/en-US/docs/Glossary/Gutters
