Responsive Design’s Dirty Little Secret

by John Albin Wilkins

The truth is that fluid grids are broken. Well… perhaps just cracked a bit. Responsive Web design, as Ethan Marcotte defines it, is simply a fluid grid, fluid images and media queries. But fluid grids have a dirty little secret: rounding errors. As we lay out our columns in percentages, browsers have to translate that into actual device pixels to fit in the viewport. And Chrome, Safari, other WebKit browsers, Opera, and the usual suspects (IE 6 and 7) all produce “errors”.

I put errors in quotes, because the issue actually has to do with the CSS spec. It doesn’t specify how browser vendors should deal with percentages that contain decimal place precision. For example, with a 6 column grid, each column is 100% ÷ 6 = 16.666667% wide. On a 1000 pixel wide viewport (which I’ve conveniently picked to make our math easier), that calculates to 166.66667 pixels per column. Since the spec gives no guidelines, browser vendors are free to make their own rules. If a browser were to round to the nearest pixel, in our example, we’d arrive at 167 pixels. But since 167 x 6 = 1002 pixels, we’d no longer have room for all 6 columns in our viewport. Alternatively, if a browser rounded down to 166 pixels per column, we’d be 4 pixels short of perfectly fitting all columns into our viewport.

Responsive Design's Dirty Little Secret image

IE 6 and 7 took the former strategy, which meant layouts often broke completely as the final grid item in a row ran out of room in its parent container and was forced to the next row. This failure is legend. See figure 1. Taking the later strategy, Webkit browsers calculate all the values and then round down to the nearest whole pixel. Thus, avoiding the potential for layout breakage. Opera, on the other hand, simply takes the 16.666667% value from our stylesheet, rounds it down to 16% first and then does the calculations to arrive at a 160 pixels per column, a full 6 pixels off of what you’d hope. Before you start swearing at the Opera developers, remember again that the CSS spec provides no rules for “the right way” to do any of this.

How bad could it get?

Unfortunately, if you use percentage-based gutters and padding, the problem gets even worse. Most layout methods in CSS float items next to each other. Which means the exact positioning of a grid item is dependent on all of the calculations done on the items before it in the row. If you had a 12 column grid with percentage-based margins and padding, that means the 12th column in a row is dependent on the margin-left, padding-left, width, padding-right and margin-right calculations of its 11 preceding columns. Add the margin-left of the 12th column itself and that's 56 opportunities for rounding errors while determining which pixel the 12th column should be placed at. In other words, your 12 column could theoretically be 56 pixels to the left of where it should be. No wonder, I’ve seen front-end developers swearing in Twitter.

Given this shocking little fact, it’s no wonder that so many of the examples of responsive design on mediaqueri.es have no obvious “box” wrapping designs that might make the flaw obvious in some browsers.

To explore these errors yourself, you can view the 10-column demo page that exposes the rounding errors in various browsers.

What the %%%% do we do?

First off, let me address all of you adaptive Web design advocates who are jumping up and down screaming, “I know! I know!” Yes, using an adaptive design approach instead of a responsive one is an obvious work-around. Adaptive Web design doesn’t use a fluid grid, so it’s completely immune to fluid grid rounding errors. Instead adaptive designs pick a series of specific viewport widths they support and those viewports that don’t exactly match those widths get the fixed-pixel layout for the next smallest layout that the design does support. I won’t get into the debate of adaptive versus responsive, I just wanted to mention that adaptive design is a perfectly fine work-around.

The best solution

You’ll notice that I didn’t include Firefox in the list of browsers with rounding problems. Firefox implements a rather innovative solution called sub-pixel rendering. Instead of rounding everything to whole pixels and allowing the errors to compound, Firefox will retain the sub-pixel values for all CSS properties and when an element's positioning depends on the properties of previous elements, the sub-pixel values will be used in the calculations. The effect is much more pleasant and inline with designers’ expectations.

IE8 introduced sub-pixel rendering apparently in reaction to how poorly they handled layouts with their former “round up” strategy in IE7 and earlier. WebKit and Opera, with their “round down” strategy, have yet to adopt sub-pixel rendering.

One option is that you could wait for all the browser vendors to replicate the sub-pixel rendering solution, but we’ve have been waiting for over 4 years for that to happen. I’m looking forward to the fix, but I’m not waiting for it either. Fortunately, there’s three workarounds you can implement today.

Wait…what about CSS3 flexbox?

Since we’ll still be using percentages to implement a responsive design with flexbox, it will still be susceptible to rounding errors. Flexbox is not a layout panacea.

Remove some of your percentage values from your design

First off, admit it, dealing with percentage-based gutters and padding is only fun for the truly anal-retentive. Our font sizes are not varying based on the viewport size (usually) and, in order to achieve a proper sense of aesthetics, our gutters should be proportional to the text size. Having gutters that expand as the viewport size increases means we have to add a small battalion of minor breakpoints to force the gutters to behave.

But there’s a little known CSS property called box-sizing: border-box. Palantir’s own Patrick Grady showed me this property last summer and it changed my life. In the CSS2 box model, padding and borders are external to an element’s width. This meant that if we set an element’s width to a percentage of its parent’s width, we were forced to also use percentages for the margins and padding of that element. Otherwise, the math just wouldn’t work out. 4 columns at 20% plus 30px gutters can never equal 100%.

With border-box, you change the box model for that element so that padding and border are now internal to its width. This means you are no longer forced to use percentages and you can now use a fixed a rem, em or pixel value for padding (that I would recommend be proportional to your content; e.g., the font-size). The compromise here is that you have to use padding for your gutters instead of margins. But I feel the advantage of making your gutters proportional to your content outweighs the disadvantage of needing a wrapper element when you want the edge of a styled box to align to a grid line. The former is needed all the time, the latter only occasionally.

So, when using border-box, you no longer have rounding errors from margins (because you’ve stopped using them for gutters) and from padding. However, there’s still rounding errors on the widths. But we’ve reduced the theoretical rounding error on our 12th column from 56 pixels down to 11 pixels. Better, but the result is still noticeable to most users.

Don’t allow rounding errors to compound

The real problem with rounding errors is their compounding nature when doing layout. In order to calculate the left edge of a grid item, we have to add up all of those values of its sibling grid items. What if we could instead just specify the left edge directly? In other words, could we just specify the distance from the left inner edge of the parent container while still allowing the item to affect the flow of the rest of the document?

It turns out you can. I’ve been using a technique since about 2004 that allows “container-relative floats”. It’s also the primary layout mechanism used in Drupal’s Zen theme which has over 700,000 downloads, so, though it may initially look too clever by half, it is extensively tested and solid.

The basic recipe to get container-relative floats is to apply this CSS to each grid item within the containing element:

float: left;
margin-right: -100%;

Then, for each grid item, simply specify the exact distance you want from the container’s left edge, using margin-left.

Here’s a quick example of this “negative 100 percent”

.item1 {
  float: left;
  width: 40%; /* 2 columns in a 5 column grid */
  margin-left: 0;
  margin-right: -100%;
}
.item2 {
  float: left;
  width: 40%;
  margin-left: 40%;
  margin-right: -100%;
}
.item3 {
  float: left;
  width: 20%; /* 1 column in a 5 column grid */
  margin-left: 80%;
  margin-right: -100%;
}

(Note that you can also position a grid item relative to the right edge of the container by floating it to the right and using a positive margin-right and a -100% margin-left.)

Negative margins diagram

How does this work? First, recall that percentage-based margins are relative to the containing block’s width, so “-100%” means we’re using the width of the container. Next recall that the right margin of floated items affects other items floated next to it. If you use were to use margin-right: -10px, adjacent floats would be relative to this right edge minus 10 pixels. Logically, “-100%” means adjacent floats would be relative to the right edge minus 100% of the container’s width. This should mean that the “relative edge” is well to the left of the container’s left edge. However, the container’s left edge will prevent adjacent floats from even seeing the relative edge when it is so far outside the container. Long story short, each adjacent float no longer sees the right edge of its siblings; it only sees the left inner edge of the container.

If you think this sounds an awful lot like absolute positioning, you’re missing the crucial difference. Absolutely positioned items are completely outside of the flow of the document and have no way to affect the positioning of other items. But container-relative floats can still be “cleared”. This is the crucial point. While floated items with this technique can no longer see each other’s right edge, they can still see their bottom edges when clearing. And it means you can start a new row of grid items by simply clearing the previous grid items and this new row will be positioned below all the previous content. That’s not possible with absolutely positioned items.

Since our grid items are no longer affected by the adjacent edges of its siblings, we are no longer as constrained by source order. What prevents us from putting the first item in our HTML source in the middle grid column and then randomly distributing the next items to the left or right of the first? Absolutely nothing. Within a single row of grid items, the HTML source order no longer defines the visual source order. All without the need for “push” and “pull” classes found in layout methods like 960.gs.

So… did we fix all our rounding errors? Not quite. We’ve reduced our positioning calculations to just one value. But that one value is still subject to a rounding error, which means we will sometimes see a one pixel error. Fortunately, due to the non-OCD nature of most website users, this one pixel error is usually unnoticeable.

If your content is quality, no one will notice a one pixel design error.

But there‘s one last work-around you can implement to reduce even this one pixel error.

Fixing the last one pixel error? Cheat.

If all of your grid items are floated left, all of your left edges should align. So you'll likely see that one pixel error on the right side of the right-most grid item. If this right edge is supposed to align with other items in other rows, this one pixel error still might be noticeable even to non-designers. But guess what? We can align all of those right edges perfectly if we float all of those items to the right instead of floating them left. Guess which browsers give a rounding error when calculating margin-right: 0%? Not even IE6.

That work-around will place the rounding error in the middle of our page where its less noticeable. More generally, you have some level of control over where the rounding error occurs, so place it where it’s less of an issue.

Zen Grids

I recently wrote a manifesto about why building responsive designs requires a CSS preprocessor like Sass. Using Sass simplifies a lot of the layout design we need to do, while simultaneously hiding the complexity we would otherwise have to deal with when writing in raw CSS.

So how does Zen Grids deal with these rounding errors? With Zen Grids, the box-sizing: border-box is the default gutter method and the container-relative floats are done automatically for you. And changing the direction of the floats for a grid item as easy as adding “right” to its zen-grid-item() mixin.

Since I’ve been using Zen Grids (and its predecessor) for years, I wasn’t even aware that rounding errors were so much a problem for fluid grids until about a month ago.

And now, with these techniques, rounding errors won’t be a problem for you either.

Additional information on how to create responsive sites using Zen Grids and the Zen 5 Drupal theme can be found in this hour-long webinar I presented with the folks at Acquia on July 19: http://www.acquia.com/resources/acquia-tv/conference/creating-responsive...

Comments

Nice write up. The title's a bit off, since it's no secret and it's certainly not Dirty ;)

The one other important point to mention is browser zoom, even if you avoid pixel gaps from rounding errors at 100%, zooming to 125% or whatever can introduce them.

This reminds me of a solution to font-sizing issues from a few years ago too - size everything in multiples of ten so it always rounds evenly in all browsers!

Even though this article is focused on new ideas, percentage-based grids, responsive design, border-box, I feel like it's is a bit dated. To me, it's dated in the sense that it's talking about trying to impose pixel-perfect precision into an inherently fluid world - the web has always been flexible as a quick html page with some text (no CSS) will show.

I think it's important to shift focus from pixel-perfection to flexibility and simplification, and it's our job as designers to make this happen by removing the constraints we're creating for ourselves by imposing this idea that we must dated tools like grids. Grid systems come from the print world, don't they?

So perhaps we can focus on thinking of new ways to adapt design on the web rather than trying to fit the new medium to the past methods. Let's agree that browsers will never render our code as perfect as we intended and let us agree that we'll never know how big or small viewports will be and then let's design and code around that method of thinking.. Not to sound cliche as all hell, but let's think outside the box.

Fluid grids are a cornerstone of Responsive Web Design. And grids are a print-era refinement of the pre-print-era’s hand-written columns of text used in scribed books. Fluid grids allow us to use the learning of the past and adapt it in a new way to new flexible viewports. (Our first attempt of applying grids was to try to use a fixed grid size on an inherently fluid medium, so I think we're getting better at this.)

If we don't use grids or columns to layout our words and content, what do you propose as an alternative?

In the meantime, these rounding errors will remain with us until these browsers' usage drops to IE7 levels. So, why not fix them?

John, thanks for your reply..

I suppose the goal for my comment was to put more emphasis on shifting responsibilities to designers to solve these challenges. If we know the web's limitations, maybe we can design around them rather than beating them into submission with code. Perhaps we can design simplified content that are easier to manage code side? Maybe we can just accept these faulty imperfections that are inherent in the web? I actually don't have an elegant alternative - maybe we'll try working with grids a bit longer and find something better?

As a community, we're currently leaving a workflow where we worked with a fixed page layout (960 typically) and moving towards a fluid / responsive layout. I think it's great, but it's my personal nature to question everything. Luke Wroblewski recently said, any time a new mass media device is introduced to our society we try to apply the thinking of the old device to the new one. For example, when TV was first invented, we used it like a radio until we found out it could do so much more.

So along this vein of thinking I'm just opening up conversation to a change in thinking. I actually don't have an alternative.. I wish I did. Thanks again for your reply. I hope my comments aren't coming off as unappreciative of your article.

Luke's site is here: http://www.lukew.com/

I think I understand and agree with you, Nick. You see, I come from a long time (since 1994) when virtually there weren't any gaps between designers and frontend developers, as normally one would do the whole job by himself. And today I design most of the websites I'll have to code later and sometimes design websites for other people to code it.

So when I'm designing these websites today, I usually try and avoid making things that I know will overcomplicate coding it later. Or sometimes, I really want something that is normally complicated to code, so I begin to explore options that may make coding it simpler and come with some unexpected design solution to achieve the result I'll want. With this approach I'm able to design some nice layouts which are much simpler to code and maintain.

So, grids, yeah. I like and use them, a lot. But designers are to be responsible and not blindly making layouts which mimic print media and screw the developers who will have to code and maintain them later. We must remember that designing is to think and propose viable solutions. And solutions not only to our clients and users needs, but also to our whole industry.

Wow, thank you for summarizing this complex issue.

And the right margin -100% declaration is really clever.

Does Zen Grids use ems for column sizing? Any interest in extending it if not? I've been thinking that em-based media queries and grids might be a very powerful combo along with the clever workarounds for rounding issues.

Lyza Gardner’s article on em-based media queries ( http://blog.cloudfour.com/the-ems-have-it-proportional-media-queries-ftw/ ) came out just before the 7.x-5.0 release of the Zen theme. I've been playing with these media queries, but its not implemented in the Zen Theme. And there's nothing in Zen Grids that prevents you from using em-based media queries.

I'm not sure I see the need for using ems for the column sizing. Responsive design uses percentages for the grid columns. With em-based media queries, what's the need for em-based column sizing too? ems are fixed sizes like pixels. A fluid grid requires a percentage unit on the grid columns.

I recently switched as many of our in development sites to EM-based media queries. The problems with pixel based MQs are not immediately apparent until you change the default text size in the browser from 16px to something else. Try something drastic like 24px. When pixels are used, a change in font size will not trigger a change in layout. Depending on how you decided upon your site's breakpoints, your layout will break down. Try it with a site you've designed or a RWD site that you frequent and you'll see what I mean.

We design with EMs for font-sizes so that we don't override a user's preference. If they prefer 18px or 20px as their font size in their browser because they find most text hard to read, than we should honor that. And if our media-query breakpoints are not flexible, these users may encounter a broken experience.

I found this extremely helpful as I'm currently evaluating different base themes to use in our next design iteration. Thank you!

Will this be among Acquia's recorded webinars? I hope so, thanks for doing this!

Yes, I believe the webinar will be recorded. We’ll update this blog post once the video is up.

I ran into a snafu today working with positioning multiple images in a header and the float; left; -100% margin; technique was the only solution I could find that worked on the responsive theme. Thanks!

If you reserve room (padding on the wrapper), you can make it so that at least one column does not need an explicit width while still showing liquid behavior. It's an old technique including floats and negative margins, a lot easier that the technique you describe above.

I love articles that show off clever code. There are many ways to solve problems in coding, but this is definitely as the article says: elegant. I can't wait to try it out.

The rounding drives me crazy! I hope the browser vendors can all implement a standard soon. As you mentioned Firefox (and IE) seem to have this down in more current versions. I want a solid backbone to my designs and I don't want to have to think about this rounding anymore. It is crazy how much complexity there is to do something that appears so simple for today's websites ... that play nice on different viewports (at least for creating a boilerplate for rapid and consistent development).

If webkit (Safari and Chrome) would use the FF/IE sub-pixel handling methods, life would be better for the designer!

Great reading, john.

I was looking for a better grid system for the next version of Sasson, and zen-grids was always in my mind, for primarily the two reasons you mention here:
* no actual (margin) gutter - using my fluid version for 960gs, I usually set gutter width to 0 to minimize these math errors.
* no push/pull/alpha/omega mixins - those are *not* very user friendly.
now I start thinking my search is over.

Two things I'd like to ask:
* Since (IMO) using floats for layout is a hack, and it's only a matter of time before we demonize them tables-style - did you ever considered an alternative ?
* Don't you agree zengrids.com deserves a better design ? maybe I can help with that...

"Since (IMO) using floats for layout is a hack, and it's only a matter of time before we demonize them tables-style". Inline blocks (the alternative suggested in the linked article) have serious whitespace issues (every run of space or return characters is essentially its own inline block too.) So I actually completely disagree with the premise of floats being a hack. Its no more of a hack then any other layout solution we had in CSS2.1. Alternatives? The next best thing is flex-box, but that's still years away to wide browser support.

"Don't you agree zengrids.com deserves a better design?" Hell, yes! As you can tell from the cat pics, I'm not a designer. CSS is my forte. I would love some help with a better design! Please! Please!

Thanks for this extensive description. I had the exact same problem at my website with the main navigation, but didn't care about the rounding errors. It seems that Chrome has also switched to sub-pixel rendering in the meantime since the "rounding error gap" isn't evident anymore.

Funnily I have discovered something completely new in your article, namely container-relative floats. Although you use it since 2004 I have never heard about it. Thanks for the tip!

I am very excited about this margin-right: -100% method. Very cool.

I have been doing some extensive testing with it, and found that margin-right: -100% will destroy layouts in IE 7. For some reason, -100% is just too much for it, and everything appears to collapse in on itself.

So instead, for IE 7 (IE 8+ does not have this problem), use margin-right: -99.9%. The difference is almost imperceptible, and it seems to work in all instances I have tested.

Thanks for the awesome post John!