Device-Agnostic Approach To Responsive Web Design

This article was first published on smashingmagazine (03-22-2012).

This is a different take on Responsive Web design. This article discusses how we can better embrace what the Web is about by ignoring the big elephant in the room; that is, how we can rely on media queries and breakpoints without any concern for devices.

The Challenge

Let’s start our journey by looking at these online tools:

Those pages let people check websites through a set of pre-built views based on various device sizes or orientations. BriCSS goes one step further as it allows you to “customize” viewports by setting any dimensions you want.

Now check the-great-tablet-flood of 2011.

Do you get my drift? Trying to check layouts against specific sets of dimensions is a losing battle. Besides, using existing devices to set break-points is not what I’d call a “future proof” approach, as there is no for standard sizes or ratios.

I don’t want to go the “consider it to be harmful” route, but I want to point out that tools like these, or articles promoting a device approach (i.e. Device Diagram for Responsive Design Planning), make people focus on the wrong end of the problem, reinforcing the idea that responsive is all about devices.

To me, it seems more realistic to check our layouts through viewports of arbitrary dimensions and shapes. We don’t need anything fancy, we can simply drag the bottom right corner of our favorite desktop browser to enter: “Device Agnostic Mode”.

The Goal

The goal is to surface content, to style boxes as columns so they bring sections above the fold. The question is: when should we bring a box “up”?

Content Is King!

If we consider that content is king, then it makes sense to look at it as the corner stone of the solution. In other words, we should set break-points according to content instead of devices.

The Principle

The content of a box dictates its width. It is the minimum width of adjacent containers that create break points (a size at which we can display boxes next to each other).

Decisions are made keeping these points in mind:

In Practice

Markup

For this exercise, we will consider 5 main blocks:

<div class="grid-block" id="header"></div>
<div id="wrapper">
    <div class="grid-block" id="main"></div>
    <div class="grid-block" id="complementary"></div>
    <div class="grid-block" id="aside"></div>
</div>
<div class="grid-block" id="contentinfo"></div>

The wrapper will allow us to:

CSS

To build our grid we will rely on display:inline-block mainly for horizontal alignment and inline flow. But note that this choice also gives us an extra edge to play with (more on this later).

Also note that we will override this styling with float to achieve some specific layouts.

body {
    /* you'll see why later */
    margin:auto;
    /* to center align grid boxes */
    text-align:center;
    /* webkit: collapse white-space between units */
    letter-spacing: -0.31em;
    /* reset IE &lt; 8 */
    *letter-spacing: normal;
    /* IE < 8 and gecko collapse white-space between units */
    word-spacing: -0.43em;
}
.grid-block {
    /* reset */
    letter-spacing: normal;
    /* reset */
    word-spacing: normal;
    /* reset */
    text-align:left;
    /* styling all grid-wrapper as inline blocks */
    display:inline-block;
    /* aligning those boxes at the top */
    vertical-align:top;
    /* IE hack to mimic inline-block */
    *display:inline;
    /* part of the above hack for IE */
    zoom:1;
    /* boxes would shrink-wrap */
    width:100%;
}
/**
 * rules below are meant to paint the boxes
 */
.grid-block {
    height: 150px;
}
#header {
    background: #d6cac1;
}
#main {
    background: #ad9684;
}
#complementary {
    background: #7a6351;
}
#aside {
    background: #000000;
}
#contentinfo {
    background: #3d3128;
}

This produces a bunch of rows

Content-Driven Process

We define the width of each box according to its content. These values will then be used to set breakpoints. Note that the values below take into consideration a 10px gutter between columns.

Header
content: logo, navigation, search box
type: banner
minimum width: n/a
maximum width: n/a
Main
content: diverse (article, blog entry, comments, etc.)
type: main box that holds the meat of the page
minimum width: 420px [1]
maximum width: 550px [1]
Complementary
content: directory entries, tweets, etc.
type: multi-line text box with media
minimum width: 280px
maximum width: 380px
Aside
content: Ads
type: 230px wide images
fixed width: 250px or 490px (2 ads side by side)
Contentinfo
content: resources, blog roll, etc.
type: lists of links
minimum width: 220px
maximum width: 280px

The minimum and maximum widths above only come into play when the box is displayed as a column.

Breakpoints

The width of the containers establishes our breakpoints. Breakpoints are viewport’s widths at which we decide to display a box as a column (instead of a row).

How Do We “Pick” Breakpoints?

Until we are able to use something like grid layout, we are pretty much stuck with the HTML flow, and thus should rearrange boxes while respecting their source order. So we go down our list, and based on the minimum width values, we create various combinations. The values below show widths at which we rearrange the layout, styling rows as columns, or changing the width of a specific column.

470px

530px

700px

or:

950px

1170px

1190px

1410px

All of the above are potential breakpoints — each value could be used to create different layouts for the page. But is that something we should automatically do? I think not. At least not without considering these two points:

How close are the breakpoints?

We have 2 that are 20 pixels apart (1170px and 1190px); should we set both of them or should we drop one? I think that above 900px, chances are that desktop users may easily trigger a re-flow in that range, so I would not implement both. In other words, I think it’s okay to go with close breakpoints if the values are below 800px — as there is less chance to confuse users when they resize their browser window.

Should we try to create as many columns as we can?

Bringing more ads above the fold may make more sense than bringing up a list of links that you’d generally keep buried in your footer. Also, you may choose to give more breathing room to your main content before bringing up boxes that the user does not really care for.

Getting Ready for Media Queries

For the purpose of this article, we’ll use every single one of our breakpoints to create a new layout, which should also demonstrate that it is not necessarily a good idea.

/**
 * 470
 */
@media only screen and (min-width: 470px) and (max-width: 529px) {
    #aside {
        width: 250px;
        float: left;
    }
    #contentinfo {
        display: block;
        width: auto;
        overflow: hidden;
    }
}

/**
 * 530
 */
@media only screen and (min-width: 530px) and (max-width: 699px) {
    #wrapper {
        display:block;
        margin: auto;
        max-width: 550px; /* see comment below */
    }
    #complementary {
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        padding-right: 250px;
        margin-right: -250px;
    }
    #aside {
        width: 250px;
    }
}

/**
 * 700
 */
@media only screen and (min-width: 700px) and (max-width: 949px) {
    #wrapper {
        display:block;
        margin: auto;
        max-width: 830px; /* see comment below */
    }
    #main {
        float: left;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        padding-right: 280px;
        margin-right: -280px;
        height: 300px;
    }
    #aside,
    #complementary {
        float: right;
        width: 280px;
    }
    #contentinfo {
        clear: both;
    }
}

/**
 * 950
 */
@media only screen and (min-width: 950px) and (max-width: 1169px) {
    #wrapper {
        display:block;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        padding-right: 250px;
        margin: auto;
    }
    #main {
        width: 60%;
    }
    #complementary {
        width: 40%;
    }
    #aside {
        width: 250px;
        margin-right: -250px;
    }
}

/**
 * 1170
 */
@media only screen and (min-width: 1170px) and (max-width: 1189px) {

    #main,
    #complementary,
    #aside,
    #contentinfo {
        float: left; /* display:inline here leads to rounding errors */
    }
    #main {
        width: 36%;
    }
    #complementary {
        width: 24%;
    }
    #aside {
        width: 21%;
    }
    #contentinfo {
        width: 19%;
    }
}

/**
 * 1190
 */
@media only screen and (min-width: 1190px) and (max-width: 1409px) {
    #wrapper {
        display:block;
        box-sizing: border-box;
        padding-right: 490px;
        margin: auto;
    }
    #main {
        width: 60%;
    }
    #complementary {
        width: 40%;
    }
    #aside {
        width: 490px;
        margin-right: -490px;
    }
}

/**
 * 1410
 */
@media only screen and (min-width: 1410px) {
    body {
        max-width: 1740px;
    }
    #wrapper {
        float: left;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        width:100%;
        padding-left: 17%;
        padding-right: 16%;
        margin-right: -16%;
        border-right: solid 250px transparent;
    }
    #header {
        float: left;
        width:17%;
        margin-right: -17%;
    }
    #main {
        width: 60%;
    }
    #complementary {
        width: 40%;
    }
    #aside {
        width: 250px;
        margin-right: -250px;
    }
    #contentinfo {
        width: 16%;
    }
}

For the 530px and 700px breakpoints, there is a design choice to make. Without a max-width, we’d get everything flush, but the main box (#main) would be larger than the maximum width we originally set.

Demo

Please feel free to check out the Demo of this technique

The last thing to do is to create a layout to cater for IE6/7/8, as these browsers will ignore the media queries. To do so, we can use a Conditional Comment:

<!--[if lt IE 9]>
    <style>
    body {
        margin: auto;
        min-width: 850px;
        max-width: 1000px;
        _width: 900px;
    }
    #main {
        width: 55%;
    }
    #complementary {
        width: 25%;
        *margin-right: -1px; /* rounding error */
    }
    #aside {
        width: 20%;
    }
    #contentinfo {
        clear:both;
    }
    </style>
<![endif]-->

Conclusion

Not once in this article I referenced the width of a device, be it an iPad, a Xoom, or something else. Building a “content-aware grid” is a simple matter of choosing the “layout patterns” that you want, based on breakpoints that you set according to page content.

After I sent this piece to Smashing Magazine, I ran into Deciding What Responsive Breakpoints To Use by @Stephen_Greig. So obviously, we are at least two who share the sentiment that relying on devices to create layouts is the wrong approach. But I’m curious to know what everyone else is doing, or even thinking? If we had more people pushing for this, the community could be less device-centric, and could start focusing on content again.

Next Step: Responsive Media

  1. According to Ideal line length for content this box should be styled width a min-width of 25em and a max-width of 33em. So if your base font-size is 16px (as it should be), this translates as 400 pixels and 528 pixels.