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:
<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:
@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:
- nest elements
- write queries to ensure margins and gutters (white space between rows and columns) remain equal,
- 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:
.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:
.user-profile__username {
grid-area: name;
}
.user-profile__avatar {
grid-area: avatar;
}
.user-profile__bio {
grid-area: bio;
}
Now a simple media query to rearrange the grid template will handle our responsive layout:
@media (max-width: 700px) {
.grid {
grid-template-areas:
'name'
'avatar'
'bio';
}
}
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 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:
@media (max-width: 700px) {
.grid {
grid-template-areas:
'avatar'
'name'
'bio';
}
}
Furthermore, we can rearrange the grid areas in any arbitrary layout with that
single rule, and because the CSS grid system handles 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.