Cloud Four Blog

Technical notes, War stories and anecdotes

The EMs have it: Proportional Media Queries FTW!

If we’re going to be proportional…

A core tenet of Responsive Web Design (RWD) is fluidity and proportion. Instead of using fixed-width layouts, we enlightened web devs and designers use percentages in our CSS. Font units aren’t pixels or points anymore, they’re percentages (typically for top-level baseline reset) or, more often, ems. And yet the vast majority of us still write width-based media queries in pixels, e.g.:

@media all and (min-width: 500px) {}
@media screen and (max-width: 800px) {}

It’s a natural thought process: for windows or screens of particular width ranges, we want to flow our content in a particular way. This naturally seems like a pixel dimension. But, once again, to bring out my big hammer, what about when we look at things from a content perspective?

Folks who design for traditional reading media—where the content really is king—don’t center design decisions around the absolute width of content-holding elements so much as around the optimal line lengths for the content they’re flowing. There are some tried-and-true numbers one can shoot for that make for the “right” number of letters (and thus words) per line for comfortable human reading.

Thus actual column width is a function of font size and ems-per-line.

Baseline expectations

You may have seen the rule of thumb (useful, admittedly!) that makes the following general equation in terms of baseline font sizes in CSS:

100% = 1 em ~= 16px ~= 14pt

This means that, at your baseline, that is, before you’ve adjust font sizes in any child elements, the default font size in the browser is usually approximately 16px and usually approximately 14pt but always 100% and 1em.

If we start from a baseline of 16px, you may well wonder what the difference (beyond academic) is between a media query like:

@media all and (min-width: 400px)

and one like this, that uses ems multiplied against the 16px baseline approximation:

@media all and (min-width: 25em)

The answer, my friend, is content

Here’s the 64-dollar question or whatever:

What happens when the baseline is not 14pt/16px?

On Ye Olde Desktop Web, this situation most often comes about (“most often” is unscientific here, but I’m willing to toss out the hypothesis, at least) from user-intiated zoom in browsers. Low-sight users might do it, I know I do it when I’m surfing the web on my Mac Mini from the couch across the room. I’m not that old but, man, it’s hard to see the contents of a Wikipedia article on a 23″ monitor from 10 feet away.

As I zoom in, that is, make the text larger in my browser, I’m no longer at a 14pt/16px baseline. 100%/1em in my world is now a different number, maybe 18pt, maybe 32px. Pixel-defined content holders no longer have comfortable amounts of words per line. Pixel-defined content holders that float might wrap awkwardly as the content in them swells.

Case study: Our nav

Our creative director and CSS wizard extraordinaire, Aileen, whipped us up a beaut of a responsive new site layout. For various screen widths, our site’s nav has a few different behaviors.

In pixels at normal zoom, the nav elements fit in a line roughly at a width of around 656px. There’s generous room to detatch and float next to the logo at around 960px.

For screens/windows narrow enough that the full set of top-level nav elements would not fit on one line, we use the menu button nav pattern:

 

For screens/windows narrow enough that the full set of top-level nav elements would not fit on one line, we use the menu button nav pattern.

 

For screens/windows in a particular range that are wide enough to fit the top-level nav elements on a single line, we do that.
 

For screens/windows in a particular range that are wide enough to fit the top-level nav elements on a single line, we do that.

 

For screens/windows wide enough to fit all of the top-level nav elements horizontally and have enough room left over for our logo, we detatch and float the nav to the top right.
 

For screens/windows wide enough to fit all of the top-level nav elements horizontally and have enough room left over for our logo, we detatch and float the nav to the top right.

But what happens if a user has his or her zoom set higher?

I’ll show you a little experiment. I’m using the Chrome browser, and I’m viewing our site with a window about 670 pixels wide. With a pixel-based media query, that puts me in the second category of nav experience: all of the top level items are shown horizontally, docked to the top of the content:

 

 

OK, now I’m going to use the Zoom In command twice to make my text larger.

With a pixel-based media query:

 

 

 

With an em-based media query:

 

 

Why did this happen?

The pixel-based media query @media all and (min-width:656px) still evaluates to true with the zoomed-in text and therefore creates awkwardly-wrapped nav elements.

However, the em-based media query of @media all and (min-width: 41em) scales to the larger text size. Zoomed in like this, the browser no longer satisfies that query: we have fewer than 41ems to work with. So we deliver the menu-button nav pattern and other layout and styling appropriate for the way the text fits. Content, again, is what ends up dictating what we’re doing in the end.

You could also make the text smaller and watch the same proportional adjustments occur, in the inverse.

BTW: It should be noted that, unlike window resizes, which cause media queries to be re-evaluated immediately, you’ll need to reload the current page if you zoom in or out for em-based media queries to re-apply. My hunch is that most users who zoom a lot keep their zoom set as they navigate around different pages and aren’t changing zoom settings on a site-by-site basis. I could be wrong about that, though.

The specifics of em-based media queries

The media queries on our site are all crafted based on the approximate baseline. We played with our browser window widths, adjusting them until it looked like they were at the appropriate width to create a breakpoint at normal text zoom. We noted that pixel measurement and divided it by the rough baseline of 16px to arrive at our em units. There may well be a better way to do this math, but this seems to do the trick so far.

A device-specific aside

One of the things that spurred me toward thinking about em-based media queries was my own Kindle Touch. Through no action of my own, the Kindle browser’s default text zoom is, roughly put, high. Like newer smartphones, the Kindle has a high pixel density, 167ppi. An absolute-sized font (say, 16px) on a high-density screen is correspondingly tiny. Most smartphone browsers get around this by reporting their resolution differently for purposes of the web. An iPhone 4, for example, which has a real resolution of 640×960 and 326ppi, masquerades as 320×480 in the browser as a way to get normally-designed websites to look normally-sized and not teeny tiny. For the iPhone, 1em is still approximately 16px or 14pt, and so pixel-based media queries generally behave equivalently to em-based ones (disclaimer: that’s a broad generalization).

The Kindle Touch, on the other hand, has taken a different approach. It reports its web pixel resolution as 600×800, but its default text size is considerably larger than 16px/14pt.

Our early, pixel-based media queries for our nav looked dreadful on the Kindle. Its resolution meant that it was using our tablet-range layout, but its text was enormous, causing widespread ugliness as the pixel-width elements didn’t scale to adjust. The site looks pretty decent, however, with media queries in ems:

 

Our site looks tolerable on a Kindle Touch. That's about as good as it's going to get on that browser.
Our site looks tolerable on a Kindle Touch. That’s about as good as it’s going to get on that browser. 

 

Sadly, I did find that, as reported by Stephanie and Bryan Rieger, the Kindle considers itself to be in color, so the media query @media all and (monochrome) doesn’t match it and @media all and (color) does. Too bad! Speaking of Kindle and Stephanie Rieger, the Kindle Fire tablet’s browser is also a great cautionary tale about mistaken complacence about “standard” device screen widths like 480, here is an enlightening tweet:

 


 

Food for thought, Stephanie, food for thought…

p.s. Thanks to the observant folks in the community who have noticed that our nav, at wider widths, has drop-down elements that are not ideal in terms of usability. We‘re cooking up ideas about how to make this better! have actually made improvements to the tablet-version nav on touch devices since I started working on this post! More to come in Nav-Land.

Taking “Content First” Very Seriously

The new www.cloudfour.com site stretches content-first thinking to its academic extremes

Whereas my personal theme for the second half of 2011 was about letting content go, 2012 seems to be the year I obsess about content: what is content, what does it mean, and what does it look like? How do we go about untangling the CMS mess we’ve built over the last decade-and-a-half? How should content be marked up? Stored? Transformed? Delivered to devices and clients?

With the new Cloudfour.com site, we got a chance to Think Very Deeply about content and our mobile experience. We got to explore some of the nagging questions that keep us (well, me, at least) up at night. I’m not going to profess to have the answer, nor am I going to assert that the (long) thinking, designing and development process we endured was without convulsions or struggle1. But I think we’ve been lucky in the opportunity to dig in.

Content is content is content is content…

At its core, www.cloudfour.com is content. Human-readable content written by regular people. Being bold and brave (maybe it’s hubris), we started with content before any design happened.

We’re not, by far, the first to shout, “Hey, Content First!” That notion’s been around the block a few times. But the practical challenge lies in unmooring oneself from 15 years of executing web development and design in particular ways and trying new habits and processes on for size. What sounds straightforward—have a point first and then make it pretty—actually goes against a staggering amount of what we’ve become used to doing with our web projects.

In our case, we opted for writing and storing our content in static text files. We selected markdown for this project, specifically, pandoc-extended markdown with Cloud Four-specific post processing extensions. Phew. More on that sometime other than now. Important piece being: human-readable text in a loose but meaningful format.

What a transformation!

Our happy, respected content sits there on the filesystem, grinning mysteriously, versioned, simple, ready to serve whatever purpose it needs to serve. In our case, obviously, we want a web site, so we can transform that core content into a set of web pages to make up a site that works in web browsers.

You’ll note that a lot of this sounds like, um, duh, yeah, we’re web devs, we make web sites. But in peeling back and thinking this hard about content, web pages as HTML isn’t necessarily a given for every context that we might use this content. But let’s talk about web pages for our purposes today.

Our content is transformed using a somewhat magical tool called pandoc2, which processes it, plunks it in an HTML template and does some other miscellaneous things—out come HTML pages! These HTML pages are then pushed to the live server environment where they enjoy a performance-tuned, simple existence, just waiting for folks to look at them and enjoy their content.

Though the content changes from time to time—it’s versioned in a github repository—it isn’t actually dynamic, so serving it out of a database (here I am getting a bit pedantic again) provides more of a performance-maintenance drain than a boon. Or at least, that’s what I tell myself to feel awesome.

But what about the blog? Ain’t broke, don’t fix

As giddy as the simplicity of static content and transformations and a pure ultra magical shared philosophical language of core content makes me as a dev, I have to kneel to practicality and things that make sense sometimes.

WordPress is a blogging framework. It’s been around a long while, we’ve used it a long while, and it has the tools for, well, you know, blogging. We’re sticking with WordPress for our blog, though you may notice that our blog now lives a robustly independent existence as blog.cloudfour.com. Heck, maybe I’ll get the exciting opportunity to futz around with partially-static WordPress options with John!

There’s a lot more to talk about

The site is intensely responsive. It uses some edgy CSS selectors to get its job done semantically. The process of separating content from presentation can be deeply, deeply hard and we have stuff to say about that. We’ve spent a lot of time optimizing performance. We’ve battled specific bugs (many we knew about, some we didn’t) to get the site to look reasonably decent across a lot of devices. We are doing unprecedented things with :before pseudo elements. Our media queries are in ems.

We’ll continue to talk about the specific cool stuff we experimented with to get the new site working in upcoming posts. But I wanted to give a quick, high-level look at what we did before getting lost in the details.

Here is a nice picture

  1. Static content pages and image content, managed in a github repository.
  2. Pandoc and other transformation processing.
  3. Layout, design and behavior resources shared between static web and our blog.
  4. Blog content stored in WP database.

Thank you, Cloud Four Team

I owe a great amount of gratitude to the brilliant team at Cloud Four. Thinking the new site through and building it wasn’t always easy, fun or even sane. We had to (uncomfortably) learn new ways to do things that we were quite competent at before thankyouverymuch. There were confounding moments. It took John 327 hours or whatever to get Haskell compiled3 on our shared development server so we could run pandoc. And Aileen endured my weird experiments with SASS.


  1. Sometimes there was downright silliness as I pushed to explore the pedantic edges of what we could pull off with just content
  2. Not actually magic, but written in Haskell, which is kind of the same thing to my inadequate brain. More about pandoc here.
  3. Not actually true. But it did take John quite some time—it was hard! So, thank you, John.

The Best Mobile Web Conferences are Coming Soon

In the coming two months, Lyza and I are honored to be giving workshops and speaking at what we consider to be the two best conferences about the mobile web: Mobilism and the Breaking Development conferences. You should join us.

Here’s what you need to know.

Live in Europe or need a vacation? Attend Mobilism

You must attend Mobilism on May 10-11. We can’t speak highly enough of this conference.

Seriously, register now. If you can’t attend, please pass on the word. This is a great conference, but they need your help making sure enough people attend so they can continue to put on this event..

Discount!!! EXPIRES SOON.

You can get 10% discount on the ticket price by going to a special registration page. This offer expires March 31st.

Attend Our Workshop

Lyza and I are also giving a workshop in Amsterdam. Here is a short description:

How to get from here to everywhere: Taking your web skills mobile

OK. You already know how to wield HTML and CSS, and maybe you can juggle JavaScript and server-side technologies, too. What you need to know is how to take your existing web skills mobile—quickly.

Lyza Gardner and Jason Grigsby, co-authors of “Head First Mobile Web” (O’Reilly), will show you the leading strategies for making web sites mobile friendly, whether you’re adapting existing sites or building new ones from scratch. There is no silver bullet. But in this hands-on workshop, we’ll show you the tools that make up the mobile web designer and developer arsenal—and how to choose which tactics to use for different projects.

This is a great opportunity for you or someone on your team to learn how to build things for the mobile web. It is a day-long immersion in the tools and techniques required to deal with device diversity. Seats are limited to please register soon.

In the States? Attend Breaking Development

Come join us at the Breaking Development conference in Orlando on April 16-18. I’ve written in the past about how much we love this conference. We love it so much that we sent the entire company to the last Breaking Development conference.

Here are the highlights of why you should join us:

  • This is the only conference in the United States focused on mobile web technology.
  • Like Mobilism, the speakers list is fantastic.
  • Everyone at the conference is interested in mobile web. The conversations continue into the evening. You leave the conference buzzing with ideas.
  • I’m presenting on Smart TVs again with my The Immobile Web talk.
  • People are guaranteed to make fun of me. I’m sure this will happen at Mobilism as well, but the Breaking Development organizers have refined it to an art form. :-)

I don’t know what else to say. Register soon.

Discount!!! Limited to the first 10 people.

The first ten people to use discount code ‘ORGRI12′ will save $100 on their registration.

Attend our workshop

There is ONE and ONLY ONE seat left in the workshop that Lyza and I will be giving in Orlando. The workshop is called Zombie Apocalypse Preparedness 101. It teaches you the survival skills you need to survive the upcoming zombie apocalypse of devices. Register ASAP before the final seat is taken.

Support these conferences

If you care about the topics that we cover on this blog, then you need to support these two conferences. They are the only conferences focused exclusively on the challenges of building things for mobile devices.

Conference like this run on thin margins. I know the organizers of both conferences would like to make money, but are primarily motivated by helping our community get off the ground. If we want the conferences to continue, we have to support them.

Even if you cannot attend the conference, please pass the information on to your co-workers and friends. Tweet about it. Share on Facebook. Do whatever you can to help them out.

I would consider it a big favor if you would do so. Thanks in advance.

First thing you should do to optimize your desktop site for mobile

Bruce Lawson has great post today called What Users Want from Mobile, and what we can re-learn from them. I highly recommend reading it.

Bruce quotes from a survey of mobile web users and pulls out a few highlights including a huge demand by users for performance. Bruce writes:

This tells us that speed is more important than aesthetics. So perhaps some of the time and effort put into media queries, viewports, avoiding scrolling, line length would actually be better employed reducing HTTP requests and optimising so that websites are perceived to render faster.

Exactly.

This echoes something Brad Frost and I were talking about the last time I was in New York.

If you could only do one thing to prepare your desktop site for mobile and had to choose between employing media queries to make it look good on a mobile device or optimizing the site for performance, you would be better served by making the desktop site blazingly fast.

Most mobile browsers are pretty good about providing tools to help someone utilize a design meant for desktop on a small screen. People can double-tap or pinch and zoom to see and read the content.

But if your site is a bloated mess, there is nothing people can do about it. There is no magical gesture that people can invoke to make something load faster if the developer hasn’t built the site for speed in the first place.

The only gesture they are likely to use involves a single, upright finger as they ditch your site for one that responds to their requests in a timely fashion.

How Apple.com will serve retina images to new iPads

One of the more interesting questions raised by the new iPad and its retina display is whether or not web sites should deliver higher resolution images when there is no way to know the connection speed. AppleInsider found that Apple.com is being prepped to deliver high-res images and documented how you can test it in Safari on your desktop.

As you can imagine given my research on responsive images, I was keenly interested to see what approach Apple took.

What they’ve chose to do is load the regular images for the site and then if the device requesting the page is a new iPad with the retina display, they use javascript to replace the image with a high-res version of it.

The heavy lifting for the image replacement is being done by image_replacer.js. Jim Newberry prettified the code and placed it in a gist for easier reading.

The code works similarly to responsive images in that data attributes are added to the markup to indicate what images should be replaced with high-res versions:

1
2
3
4
5
6
7
8
9
10
11
12
13
<article id="billboard" class="selfclear" data-hires="true">
  <a id="hero" class="block" href="/ipad/">
    <hgroup>
      <h1>
        <img src="http://images.apple.com/home/images/ipad_title.png" alt="Resolutionary" width="471" height="93" class="center" />
      </h1>
      <h2>
        <img src="http://images.apple.com/home/images/ipad_subtitle.png" alt="The new iPad." width="471" height="54" class="center" />
      </h2>
     </hgroup>
     <img src="http://images.apple.com/home/images/ipad_hero.jpg" alt="" width="1454" height="605" class="hero-image" /> 
  </a>
</article>

Unlike most of the solutions I reviewed last summer, Apple is applying the data-hires attribute to the parent container instead of to the images to themselves. Also, the images borrow from native iOS development and have consistent sizes. So the high-res version of ‘ipad_title.png’ can be found at ‘ipad_title_2x.png’.

As far as I can tell, there is no attempt to prevent duplicate downloads of images. New iPad users are going to download both a full desktop size image and a retina version as well.

The price for both images is fairly steep. For example, the iPad hero image on the home page is 110.71K at standard resolution. The retina version is 351.74K. The new iPad will download both for a payload of 462.45K for the hero image alone.

The total size of the page goes from 502.90K to 2.13MB when the retina versions of images are downloaded.

Another interesting part of image_replacer.js is that it checks for the existence of 2x images before downloading them:

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
    requestHeaders: function (c) {
        var a = this;
        if (typeof a._headers === "undefined") {
            var b = new XMLHttpRequest();
            var a = this;
            src = this.hiResSrc().replace(/^http://.*.apple.com//, "/");
            b.open("HEAD", src, true);
            b.onreadystatechange = function () {
                if (b.readyState == 4) {
                    if (b.status === 200) {
                        a._exists = true;
                        var f = b.getAllResponseHeaders();
                        a._headers = {
                            src: src
                        };
                        var d, e;
                        f = f.split("r");
                        for (d = 0;
                        d < f.length; d++) {
                            e = f[d].split(": ");
                            if (e.length > 1) {
                                a._headers[e[0].replace("n", "")] = e[1]
                            }
                        }
                    } else {
                        a._exists = false;
                        a._headers = null
                    }
                    if (typeof c === "function") {
                        c(a._headers, a)
                    }
                }
            };
            b.send(null)
        } else {
            c(a._headers, a)
        }
    },

This is probably necessary as they move to providing two sets of assets in case someone forgets to provide the retina image. It prevents broken images. Unfortunately, it means that there are now three http requests for each assets: a GET request for the standard image, a HEAD request to verify the existence of the retina image, and a GET request to retrieve the retina image.

Web Inspector timeline showing additional HEAD request for 2x image

Another interesting bit of image_replacer.js is when they decide to go retrieve the double-size image:

26
if ((this.options.debug !== true) && ((typeof AC.Detector !== "undefined" && AC.Detector.isMobile()) || (AC.ImageReplacer.devicePixelRatio() <= 1))) {

Of particular interest is the test for AC.Detector.isMobile(). This is defined in a separate script called browserdetect.js (prettified gist version).

The browserdetect.js is full of user agent string parsing looking for things like operating systems and even versions of OS X. The isMobile() function does the following:

166
167
168
169
isMobile: function (c) {
  var d = c || this.getAgent();
  return this.isWebKit(d) && (d.match(/Mobile/i) && !this.isiPad(d))
},

Basically, is this a WebKit browser, does the user agent mention mobile, and let’s make sure it isn’t an iPad. Browsers not using WebKit need not apply.

Testing for yourself

AppleInsider’s instructions on how to test the retina version of Apple.com on your computer are very easy. Open Apple.com in Safari. Go to the console in the Web Inspector and type the following:

AC.ImageReplacer._devicePixelRatio = 2
new AC.ImageReplacer()

You’ll get back a klass object as shown below.

Console screenshot

As an aside, notice SVG references in the console screenshot.

What can we learn from this?

Probably not a whole lot for a typical site because our goals will be different than Apple’s.

For Apple, it probably makes more sense to show off how wonderful the screen is regardless of the extra time and bandwidth required to deliver the high-resolution version. For everyone else, the balance between performance and resolution will be more pressing.

There are a few minor things that we can take away though:

  • Planning ahead and knowing that you can depend on high-res images being available would be preferable to making extra HEAD requests to check to see if the images exist.
  • Setting priority on which images to replace first is a good idea. This is something to look at and borrow from image_replacer.js.
  • The retina version of Apple.com’s home page is four times the standard home page. Delivering retina images should be considered carefully.

Perhaps most importantly, Apple isn’t sitting on some secret technique to make retina images work well. Maybe they will provide better solutions in iOS 6. The way they handle images—downloading both sizes plus an additional HEAD request—may be the least efficient way to support retina displays. But for Apple, it likely doesn’t matter as much as it will for your site.

Hat tip to Jen Matson for pointing me to the original AppleInsider article.

Further reading