Want to see the full-length video right now for free?
Sign In with GitHub for Free AccessResponsive design is a critical approach to making sure your content is useful and readable on the increasingly large array of device sizes in use today. Tune in as Chris and Ryan discuss the ins and outs of responsive design, sharing the techniques, workflows, and thinking we use here at thoughtbot.
"Responsive design" is an approach to web design where the content and layout adapts to the various sizes of the viewport, most notably to ensure the content is displayed in a useful manner across a variety of devices such as a large screen desktop monitor, a medium sized tablet, a mobile device, and everything in between.
A great example of responsive design is the Boston Globe site. If you open that site in a desktop browser and begin to decrease the width of the browser window, you'll notice that all of the content proportionally resizes for a bit, then at a certain point there is a distinct change as it transitions from a three-column layout to a two-column layout. This combination of proportional sizing and discreet reflowing of content for specific width ranges comprise the core of responsive design.
Core to the idea of responsive design is the idea of always serving the same content, and then using CSS to adapt the content and present in the most useful and readable way for the given device width and related constraints.
We're big believers in this approach for the vast majority of content on the
web, but to briefly contrast, at the other end of the spectrum we have an
approach where the server will either redirect the user, or at least respond
with entirely different content. Often this content is served from a mobile
specific subdomain, for instance m.example.com
, sometimes referred to as
"m-dots". This is typically done by user-agent sniffing, but this is a
practice that is generally recommended against.
Further, this practice of splitting traffic and server entirely different content very often leads to a subpar experience. Redirects can lose the specific resource and dump you on a mobile index, the content is often truncated preventing you from finding the needed information, and links are now device specific. Additionally, this practice likely leads to at least double the work as you now need to maintain two separate versions of your site.
One counter-example to the recommendation to avoid mobile specific views is GitHub's mobile views. GitHub did a great job of maintaining the URL, providing a trimmed down versions of the page specifically targeted at mobile, and provides a link in the footer to explicitly request the full desktop version of the page.
In general we prefer not to use frameworks like Bootstrap (thus we created
Bourbon) due to their heavy reliance on non-semantic utility classes.
Markup like <p class="text-center">
and <div class="col-xs-8 col-sm-6">
blurs the line between the content and the formatting, effectively locking
your design into Bootstrap.
To start, we have a sample CodePen we've built to demonstrate the core ideas of responsive design. The design is a simple header, body and sidebar, then footer. The content is laid out using Slim, but it's worth noting that Slim provides none of the responsive behavior, it just happens to be well suited to defining a sparse document layout.
Core to our current approach to responsive design is the use of Flexbox. We have an Introduction to Flexbox in a previous episode of the Weekly Iteration which can get you started, but it's worth noting that flexbox does a lot of the heavy lifting and makes much of responsive design drastically easier. Flexbox provides the proportional width half of the responsive design pie by allowing us to easily designate what proportion of the parent container each child element should take up.
Media queries are a syntax for defining discreet transition points, referred to as "break points", where specific styling rules apply. Typically they take a form like:
@media (min-width: 700px) {
/* This style block will only apply on viewports larger than 700px */
margin-right: 10px;
padding: 0;
}
We can implement the rules based on a number of specifics including aspect
ratio, height, width, orientation, etc, but by far most common is to define
the rules based on either max-width
or min-width
.
To provide an example bringing flexbox and media queries together, we have the main content area which wraps the intro and sidebar blocks:
<div class="main-content">
<div class="intro">
Content
</div>
<div class="sidebar">
Sidebar
</div>
</div>
The base styling sets the parent .main-content
container to be a flex
container, then sets the widths of the intro and sidebar to be 75% and 25%,
respectively:
.main-content {
display: flex;
margin-bottom: 30px;
}
.intro {
margin-right: 30px;
flex: 0.75;
background-color: #B9C1D6;
}
.sidebar {
flex: 0.25;
background-color: #E2E9FA;
}
Already we have a responsive layout based on the flexbox managed proportional widths, but we can go a step further and use a media query to redistribute the space when the width is below 768px:
@media (max-width: 768px) {
.intro,
.sidebar {
flex: 0.5;
}
}
Here, rather than having the .intro
block be three times the size of the
sidebar, on these smaller screens we split the space equally to ensure the
sidebar doesn't become too small.
As we go further, we trip over the next break point at 520px
, targeted at
mobile devices. These rules kick in for anything below that 520px
threshold:
@media (max-width: 520px) {
.navigation {
display: none;
}
.mobile-menu-icon {
display: block;
}
}
The first thing we do is hide the main aviation icons in the header, and instead display the mobile specific navigation menu icon.
Next, we further tap into the power of flexbox to reflow our whole
.main-content
block:
@media (max-width: 520px) {
/* ... */
.main-content {
flex-direction: column;
}
.intro,
.sidebar {
flex: 1;
}
}
Here, we change the flex-direction
of the .main-content
container to
column
so the child elements stack vertically (rather than the default row
layout), and instruct each of the .intro
and .sidebar
blocks to now occupy
the full width. This is some serious magic, and why we love flexbox.
The initial implementation of this design was done using pure CSS, but in reality we always implement our designs using a compile-to-css language like Sass. Using Sass, we can add clarity and simplify our styling:
@import "bourbon";
$base-spacing: 30px;
$icon-size: 14px;
$light-purple: #E2E9FA;
$dark-purple: #A3AEC5;
// Screen sizes
$small-screen-size: 520px;
$medium-screen-size: 768px;
@mixin below($screen-size) {
@media only screen and (max-width: $screen-size) {
@content;
}
}
Here we've imported our Bourbon library to give us access to its mixins, defined a handful of variables including ones for our break point sizes, and even defined our own mixin for intuitive media queries. In addition, by using Sass we gain access to other features like nesting and calculation functions.
We can see an example of the expressiveness we gain by using Sass with the navigation styling:
.navigation {
display: flex;
@include below($small-screen-size) {
display: none;
}
}
Here we're able to nest the media query within our style block, keeping things
organized, and additionally we're able to take advantage of our width variable
and below
mixin to write the very clear @include below($small-screen-size)
break point declaration. No more confusion about whether it is above or below
the specified width!
When implementing a design in a real app, the device emulator in Chrome is a great tool to quickly test out on a number of device widths and orientations. You can check out more in the Device Emulation portion of our Weekly Iteration episode on the Chrome Dev Tools.
While the device emulator is great, it's critical to always test out your site on a real device to fully test it out.
Ready to dive in and continue learning about responsive design? These links should get you started: