We've been hearing a lot about responsive design and the future of the web recently. At DrupalCamp Montreal this September, Jen Simmons and Jake Strawn talked about why responsive design is taking hold. I was inspired to try out some of the techniques they talked about, and decided to convert evolvingweb.cm to be more responsive.

Unlike creating an iPhone app for your website or throwing together a mobile theme, applying responsive design to your existing site requires you to change the design of your website. What I thought would be a few small adjustments to the theme turned into a larger project to make our design and theme more flexible and robust.

What is Responsive Design?

Rather than designing a site that works for one screen size, or designing separate themes that work for different devices, the goal of responsive design is to build a website that adapts to the width of the user's screen and works for both large and small screens. This involves creating a flexible-width layout that will adapt as the screen size changes, and writing some CSS specific to screens with a particular size so that you can trim down or hide certain elements at smaller widths and restrict the width of the page at large screen widths.

Media Queries

Currently, the main technique for implementing responsive design is to use media queries. Media queries allow you to include CSS files based on the size of the user's screen or device. At different screen widths (or device widths), you can load different CSS files which change the layout and styling of the page. You can do this either by targeting screens with a particular minimum width, maximum width, or both.

CSS for Larger Screens

To include CSS files for screens larger than a certain width, you can use the following in your mytheme.info file:

stylesheets[screen and (min-width: 760px)][] = css/screen-760.css
stylesheets[screen and (min-width: 960px)][] = css/screen-960.css

The screen-760.css file is loaded for browsers the width of 760px, but also larger screens. It allows for a total page width of 760px and also defines a layout for the columns to fit in that width.

The screen-960.css file is loaded for any a screen width of 960px or larger. It restricts the width of the page to 960px and allows for normal-sized column widths (i.e. 640px for the main content and 320px for the sidebar). If you're converting an existing theme to be responsive, this will contain a lot of what used to be in your layout CSS file.

CSS for Smaller Screens

Include the following in your .info file to include CSS for screens smaller than a certain width:

stylesheets[screen and (max-width: 320px)][] = css/screen-320.css
stylesheets[screen and (max-width: 480px)][] = css/screen-480.css

The screen-320.css file would only be loaded for screens 320px wide or narrower. The screen-480.css file would be loaded for screens 480px or narrower. Notice that since a device that is 480px wide will load both files, it makes sense to load the screen-480.css file second so it overrides the styles in the 320px stylesheet.

CSS for a Range of Screen Sizes

You can also effectively set a range of screen sizes that your CSS will target by combining a min-width and min-width in your media query.

stylesheets[screen and (min-width: 480px) and (max-width: 760px)][] = css/screen-480-760.css

Inline Media Queries

Depending on your design, you might end up with a lot of screen-size-specific CSS files. Sometimes it's more appropriate to use several media queries within a CSS file, using the @media rule.


@media screen and (max-width: 480px) {
#page {
width: 480px;
}
}

Device Width vs. Browser Width

I should clarify that using min-width means that the CSS file will be loaded based on the browser width, so this will apply to users of large monitors who resize their browser. This is really useful for testing your responsive design, since you don't need to switch devices to see your design change, just change the width of your browser. If you only want to detect the device width only, use min-device-width or max-device-width.

It's Not Working on Android!

In addition to adding these media queries, Android devices need a 'viewport' meta tag to being able to detect their own screen width. Adding the media queries above won't have any effect on Android devices until you add this meta tag to your site. You can add it from your mytheme_preprocess_html() function using drupal_add_html_head() like this:

  $meta_viewport = array(
    '#type' => 'html_tag',
    '#tag' => 'meta',
    '#attributes' => array(
      'name' => 'viewport',
      'content' => 'width=device-width'
    )
  );
  drupal_add_html_head($meta_viewport, 'viewport');

What to do about Internet Explorer?

Internet Explorer versions 6-8 don't implement media queries. For these versions of IE, you can either implement some kind of responsive solution with javascript, or you can decide not provide the responsive layout for IE users, which the approach I took. In this case, you still need to provide CSS targeting IE so that users viewing your website on a larger device with IE will not see a full-width design. To implement this approach, the CSS you'll want to add for IE will likely be the same as what you added for screens that have a min-width of 960px (or whatever your widest page layout is). Drupal doesn't allow you to add a CSS file more than once, so you'll have to create a duplicate CSS file. My solution was to create a separate screen-960-ie.css file and use @import to include in it all the CSS from the screen-960.css file.

You can add a CSS file for IE only using the Conditional Stylesheets module. You can also add the file from your template.php file using drupal_add_css() and setting the browsers parameter.

Designing for Mobile

The instructions above will get you started adding media queries to your Drupal theme, but I think there's a lot to be said about how to actually create a 'mobile first' design. As themers, we're not used to designing and writing flexible-width themes for tiny devices. Even though you might like the idea of 'mobile first', your client probably expects you to design for standard-sized monitors and adapt the design for smaller devices afterwards.

Adapting a design to be responsive after it's fleshed out for a fixed-width screen is not an easy task. You can stack columns on top of each other at smaller widths, make certain elements smaller, and remove others altogether, but some elements are going to be hard to adapt. If you resize your browser to a smaller width, you'll notice a lot of awkward layouts (i.e. an image that takes up almost the full width of a column, with just a couple words wrapping to the right of it).

The best approach is to start thinking about how to make your theme responsive as you're designing and building it, and testing it at various screen widths as you go. This is going to be a challenge when the designer and themer are different people, especially if the designer is working exclusively in Illustrator or Photoshop.

Writing CSS for Responsive Design

Here are some tips to get you started writing CSS for responsive design.

  • Watch out for elements that are positioned absolutely. Will they overlap with other items at smaller screen widths?
  • Make sure your horizontal menus items wrap gracefully. Try centering them on smaller screens and using the CSS3 white-space: nowrap property.
  • Check the line-height on text that wraps at smaller screen widths.
  • Set a max-width for images of 100%, as well as for the HTML tag that wraps each image.
  • Set a max-width of 100% for form elements as well.
  • Watch out for elements with a fixed height or width. Try setting a min or max width or height instead.
  • Watch out for elements that are altered with javascript, including slideshows and text replacement tools.
  • Watch out for text that floats next to images. Do you need to change this behaviour for smaller width screens?

What do do with Tables and Panels

I found dealing with tables and Panels to be a huge challenge. Columns could be removed at smaller widths, or stacked on top of each other rather than sitting next to each other.

  • Panels layouts with more than one or two columns will not work well on smaller screens. Try writing CSS to remove columns or float columns differently at smaller widths.
  • If you're using grid-style Views to display non-tabular data, consider another display technique.
  • If you need to display data in a table, consider using advanced CSS techniques as described in this article.
  • Some of your mobile users will have an app for displaying spreadsheets on their device, so consider generating a CSV for users to download if you have a lot of tabular data to display.

Resources

Beyond Responsive Design

For some use cases when mobile performance is a priority, you'll probably want to go beyond responsive design and actually change the markup of the page for different devices. To get started doing this in Drupal, try the Mobile Tools or Context User Agent. However, mobile detection doesn't replace responsive design, and using device detection is probably out-of-scope for most Drupal projects.

Responsive design is really exciting and a great challenge for both designers and themers. While using a base theme that provides a responsive layout is great, it doesn't mean that you don't have to think about responsive design. We need to understand how different screen sizes effect our designs and how to meet the challenge of responsive design by creating more robust and more flexible themes.