This article is part 3 of a series on responsive design and typography systems. Read part one and part two.
In the first two articles of this series, we established a technical foundation for a scalable typographic system. I’ll briefly recap: if you’re designing websites, your first order of business is to stop using pixels and train yourself to think and code using relative units, in particular REMs. With pixels out of the picture, you can define meaningful relationships between the size of your type and other design elements using a modular scale.
With your fluid foundation in place, incrementally expand or contract the scale of your design by modifying a single property, the font-size
of the HTML
element.
Even though the code presented in my first two posts was viable in production, it wasn’t elegant, readable, or easily maintained. If we’re going to be introducing a lot of new media queries to our code base they must be easily authored. In addition, we’re going to need to globally coordinate named breakpoints, a subset of the responsive changes scattered throughout our codebase that align with major changes in our design. For example, a breakpoint that introduces a new content column or a major change in navigation.
With a bit of sass we can slice through these problems, write less code, and build interfaces that give us control over the most important aspects of our website’s design. Let’s get started!
With a flexible foundation in place, you’re going to want to introduce a lot of new media queries to scale your design. Most likely, far more than you’re used to. The optimal number of breakpoints varies from project-to-project, but it can easily take 10 or more media queries to optimize the scale of a design from phone-sized screens up through cinema displays and beyond. Take a read through Trent Walton’s Fluid Typography and Oliver Reichenstein’s Responsive Typography: The Basics to better understand when and why to adjust scale.
In css your code would look something like this:
html{
font-size: 11px;
}
@media screen only and (min-width: 600px){
html{
font-size: 12px;
}
}
/* Repeat media queries to manipulate font-size across many breakpoints */
Fortunately, we can be far more efficient using sass. To design responsive sites with a lot of breakpoints, we need sass to provide us with a declarative syntax for repeatedly manipulating properties like the root font-size
.
Here’s what I’ve put to work inside Bugsnag and on this blog:
html{
@include responsive("font-size", 11px,
(
600px: 12px,
800px: 13px,
1180px: 14px,
1300px: 15px,
1750px: 16px,
1900px: 17px,
2100px: 18px,
2400px: 19px
)
);
}
With this syntax we can read the changes happening to the scale of our design as a sentence. The the root font-size
has a default value of 11px; therefore 1rem = 11px
. With a minimum viewport width of 600px, the value of 1rem = 12px
. At 800px, 1rem = 13px
— and so on.
There are cases where you’ll want to responsively manipulate two or more properties that share the same value. For example, it can be useful to set a container element’s padding-left
and padding-right
, instead of it’s width
, so that its background can extend to the edges of the page.
#container{
width: 100%;
background: $background-color;
@include responsive("padding-left" "padding-right", 5%,
(
600px: 8%,
800px: 11%
)
);
}
Sometimes min-width media queries don’t give us the control we need. Imagine you wanted to override a default set of min-width based queries specifically on iPads in landscape mode:
@include responsive("font-size", 11px,
(
600px : 12px,
800px : 13px,
(min-device-width 768px)
(max-device-width 1024px)
(orientation landscape) : 16px
)
);
If that media query syntax looks familiar, it’s because you may already be using it in your projects via the popular Compass extension, Breakpoint. If your project includes Breakpoint, the responsive
mixin calls it to generate each of the chained media queries. That means we can use additional features of Breakpoint in our chained queries. For example, we can set a global variable, $breakpoint-to-ems
: true, to take advantage of the benefits of em-based media queries.
So far we’ve been looking at examples that use one-off values for media queries. However, it’s often important to be able to synchronize some of our media queries with changes occurring elsewhere in our design. We’ll utilize sass 3.3 maps to conveniently store our named breakpoints in a global variable $named-breakpoints
.
$named-breakpoints: (
"xs": 350px,
"s": 600px,
"m": 800px,
"l": 1420px,
"xl": 2100px,
"ipad": (min-device-width 768px) (max-device-width 1024px)
);
Now you can reference named breakpoints inside chained media queries, and fill in the gaps with anonymous media queries as necessary.
@include responsive("font-size", 11px,
(
"xs" : 12px,
450px : 13px,
1100px : 14px,
"l" : 15px,
1600px : 16px,
"ipad" : 14px
)
);
Chained media queries are a natural fit inside scalable, modular css architectures like atomic design and smacss. Instead of aggregating unrelated changes into large media query blocks, we can use SASS to independently manipulate individual properties across a spectrum of devices. Also, as long as you’re minifying and gzipping your css, the filesize impact of introducing even hundreds of new media queries is minimal.
To start chaining your media queries using sass 3.3, grab a copy of the responsive
mixin from this gist. Sass 3.2 users can grab this gist instead.
I’d love to hear what you think about chained media queries. Is the responsive
mixin a fit for your projects? Is there anything it could do better? Send us your feedback on twitter @maxluster or @bugsnag, or via email at support@bugsnag.com.