Device-Agnostic Approach To Responsive Web Design
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.
Further Reading on SmashingMag:
- Responsive Web Design: What It Is And How To Use It
- Design Process In The Responsive Age
- Responsive Web Design Techniques, Tools and Design Strategies
- 12 Factors In Selecting A Mobile Prototyping Tool
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”?
Further Reading on SmashingMag:
- Responsive Web Design: What It Is And How To Use It
- The State Of Responsive Web Design
- Design Process In The Responsive Age
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:
- The width of a box should be as small or as wide as possible without impairing readability.
- The max-width of a box should take into consideration the importance of following boxes. This is because the wider the box, the wider the viewport must be to reveal subsequent boxes.
- The goal is not to bring everything above the fold (we don’t want to fill the viewport with clutter).
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:
- mix percentages and pixels to style boxes on the same row
- set a maximum width for a group of boxes
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 {
margin:auto; /* you'll see why later */
text-align:center; /* to center align grid boxes */
letter-spacing: -0.31em;/* webkit: collapse white-space between units */
*letter-spacing: normal;/* reset IE < 8 */
word-spacing: -0.43em; /* IE < 8 && gecko: collapse white-space between units */
}
.grid-block {
letter-spacing: normal; /* reset */
word-spacing: normal; /* reset */
text-align:left; /* reset */
display:inline-block; /* styling all grid-wrapper as inline blocks */
vertical-align:top; /* aligning those boxes at the top */
*display:inline; /* IE hack to mimic inline-block */
zoom:1; /* part of the above hack for IE */
width:100%; /* boxes would shrink-wrap */
}
/**
* 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
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
- header
- Main
- Complementary
- Aside (250) + Contentinfo (220)
530px
- header
- Main
- Complementary (280) + Aside (250)
- Contentinfo
700px
- header
- Main (420) + Complementary (280)
- Aside
- Contentinfo
or:
- header
- Main (420) + Complementary (280)
- Aside + Contentinfo
950px
- Main (420) + Complementary (280) + Aside (250)
- Contentinfo
1170px
- Main (420) + Complementary (280) + Aside (250) + Contentinfo (220)
1190px
- Main (420) + Complementary (280) + Aside (490)
- Contentinfo
1410px
- Head (240) Main (420) + Complementary (280) + Aside (250) + Contentinfo (220)
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
- Polyfilling picture without the overhead
- Experimenting with Context-Aware Image Sizing
- Responsive Design Guidelines on Smashing Magazine
Footnotes
[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.
(jvb) (il) (vf)