Aaron Mentele personal blog of Aaron Mentele, web developer and partner at Electric Pulp

Media queries for mobile browsers

January 15, 2012 —

On Friday, I posted about some test cases and detailed how Mobile Safari handles redeclared assets in three situations on iOS. I did this to try to clear up the concern that using media queries led to compounding or unnecessary file downloads. There are specific cases, in older versions of the Mobile Safari, that raise valid concerns, but in most practical cases Mobile Safari’s behavior complements responsive web design (?) well. Mobile browsers have come a long way over the last few years.

Here are a few things to keep in mind:

Hiding Image Tags

You can hide an HTML tag, but you can’t prevent the asset from being requested. If you thought you’d just set that entire column of banner ads to display:none within your media query (or, simply, further down the cascade) to make a better experience for your mobile visitors, just know that, as of Mobile Safari 5.1, your audience still has to download each of the assets (e.g., images sourced in tags) that you’ve just hidden, and your advertisers might be paying for impressions you aren’t delivering.

Hiding Background Images

You can hide a CSS background image and prevent the asset from being downloaded by setting the element’s parent to display:none. Just remember, this doesn’t work if you hide the element itself. Setting the parent to display:none is an easy way to hide images without forcing pointless downloads. Mobile Safari exhibits this behavior as far back as I’ve been able to test (Mobile Safari 3).

Replacing Background Images

Another way to hide a background image is to set the background-image to ‘none’ on the element itself. Maybe you’d like to remove a background-image from your document’s , for instance. The initial asset will not be downloaded by iOS 5 Mobile Safari. This same behavior works if you’d like to declare an alternate background-image within your media query (e.g., replacing huge.png with small.png in my test cases).

You should be aware, however, that prior versions of the browser actually will download the initial asset as well as the one you declare further down the cascade. The only documentation I can find regarding this bug suggests all versions of Mobile Safari prior to 5 are affected, but I’ve seen conflicting results.

Declaring for Orientation

You can target an orientation (e.g., landscape), and the browser will only request that asset only if you start in or change to that orientation. This might be a rare situation, but it’s nice to know that, as of Mobile Safari 5, the browser will not request orientation-specific file(s) at initial page load if they aren’t needed. Being able to target iPhone orientation is new to iOS 5, so I haven’t tried testing anything other than Mobile Safari 5.

Caveat Emptor

I’m being careful to specify Mobile Safari on iOS. I’ve tested WebKit on Android with similar results, but everything you see above has been confirmed by a small army of independent tests over time. On that note, I should formally thank Jason Grigsby, Tim Kadlec and Michael Lehmkuhl for confirming each of these test cases over the weekend and Ethan Marcotte for helping me focus the test cases in the first place.

Clearly, there are more devices and browsers to test against, but I’ll never get through them all. I plan to follow up with results from Android’s WebKit and Opera Mobile once I’ve had chance to further verify. If you’d like to check on your own, I’ve posted the files I used to test four of the scenarios. You’ll just need access to your log files (access_log in my case) to confirm which files are being requested by the browser. It probably goes without saying that you’ll need to clear data / cache between each test, but I’ve noticed that even that is sometimes not enough on older devices. If you do find further results, I’d love it if you’d ping me on twitter.

Just don’t let all these caveats bury how far mobile browsers have come and how ably they handle assets today. I hear mobile is going to be a big thing.

Sirens

January 13, 2012 —

There seems to be a widely held belief that using media queries to overwrite css properties results in compounding load times (in the case of replacement assets being declared) or unnecessary load times (in the case of display properties being set to none). More likely it’s simply an uncertainty that, lacking time or reason, few have bothered to test themselves. That uncertainty gives rise to arguments against using responsive web design to handle mobile experience due to bandwidth concerns.

I’ve never found this to be the case.

In fact, the manner in which mobile browsers handle assets is one of the reasons I think responsive web design is so practical. Designing for smaller viewports typically has the added benefit of lightening page load rather than the reverse. Don’t take my word on it, though. Not yet.

It typically takes specific project requirements to get me to set up test cases, so my testing has focused heavily on iOS devices. Over time I’ve tested on iPhone 3, 3g, and 4, iPod Touch Gen 2, 3 and 4, iPad 1 and 2, and a token Nexus One. I realize that leaves the behavior of a lot of browsers in question. Caveat emptor.

Last night, I recreated the test scenarios detailed below using Mobile Safari 5 on an iPhone 4 and Mobile Safari 3.1 on an iPod Touch. I mentioned that I’ve tested on a number of devices/browsers, but given the rate of change in mobile browsers, please do not extrapolate beyond these two browsers.

Test 1

A background image is declared in css, but the parent’s element is set to display:none inside a simple media query targeting an iPhone.


.sidebar div {
  background:url(/img/huge.png);
}

@media only screen and (max-device-width: 480px) {
  .sidebar {
    display:none;
  }
}

In this case, the browser recognizes the display property and does not request/download /img/huge.png. As you’d hope.

Test 2

A background image is declared in css but then overwritten inside a simple media query targeting an iPhone.


.sidebar div {
  background:url(/img/huge.png);
}

@media only screen and (max-device-width: 480px) {
  .sidebar div {
    background:url(/img/small.png);
  }
}

In this case, the browser requests /img/small.png but not /img/huge.png. As you’d hope. UPDATE: Mobile Safari 4 may have had a bug causing both files to be downloaded (as you would not hope). I’ll add some test devices for follow up testing.

Test 3

A hybrid of Test 1 and 2 except we want a background-image to appear on orientation change.


.sidebar div {
  background:url(/img/huge.png);
}

@media only screen and (max-device-width: 480px) {
  .sidebar {
    display:none
  }
}

@media only screen and (max-device-width: 480px) and (orientation: landscape) {
  .sidebar {
    display:block;
    }
    .sidebar div {
      background:url(/img/small.png);
    }
}

In this case, the browser does not request /img/small.png unless you start in or change to landscape orientation. As you’d hope.

In short, mobile browsers are smart. The results you’ll encounter will tend to make sense.

It’s worth noting that the behavior noted above does not cover images requested via tags. If your plan was simply to hide those banner images on smaller devices, you’re going to need a better solution. Those assets are still going to be served.

UPDATE: I also need to be clear that the first test case Test 1 only works if the parent element is set to display:none. Setting the element itself to display:none will not work. The example code I used when writing this post was slightly different than my actual test files and may have been misleading.

If I was only allowed to make one point, it would be this: don’t believe any test a person uses to support a claim for or against a development practice until you’ve performed it yourself. I personally consider responsive web design to be an extremely practical way to improve mobile interface without sacrificing experience due to load time. Each of you can perform your own tests.

HTML5, again

March 17, 2010 —

If you’re a front-end developer, I want you to do me a favor. I want you to pick a project and mark it up in html5. I’m not going to ask you to code a game experience inside the canvas element or replicate a youtube video player or do anything really, except challenge you to declare semantic information about your content blocks.

This is a <header>. This is a <section>. This is a <footer>. Et cetera.

What I heard at southby any time it came up was that HTML5 wasn’t worth the extra effort. I didn’t hear a single dev concerned with browser compatibility or the possibility of the spec changing. Just effort. And that’s bullshit. You’re changing a doctype and working with a few extra block elements.

I’m going to bonus you out, though, to help convince you to do it. This all comes together and opens up a foundation for certain CSS3 enhancements. You’ve heard of @font-face, right? Yeah, read on.

Switching the doctype

It feels sexy being able to type your doctype by hand. If you aren’t already doing it, try it. <!DOCTYPE html> Sexy.

Declaring your character set just got simpler, too. <meta charset="UTF-8" />

Some of you noticed I closed that tag. I like XHTML. Maybe you don’t. You can do it either way.

Tricking out your blocks

You can tell yourself all you want that your id’s and classnames are already informing people and bots of the content type within, but you’d be kidding yourself. Div’s are for suckers. They provide no semantic information to the untrained audience. You could say the same of html5, except that it really is standard.

For those who haven’t read through the spec, here’s an example skel template:


<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Boom</title>
    <meta charset="UTF-8" />
  </head>
  <body>
  <header id="header">
    <hgroup>
      <h1>BOOM</h1>
      <h2>I'm using HTML5!</h2>
    </hgroup>
  </header>
  <nav>
    <ul>
      <li><a href="">a link</a></li>
      <li><a href="">a link</a></li>
    </ul>
  </nav>
  <section id="content">
    <article>
      <header>
        <h3>Implementing new markup is fun.</h3>
      </header>
      <p>I can't believe how excited I am right now.</p>
      <aside>
        <p>Related: I like CSS3 too, but Imma let you finish.</p>
      </aside>
      <footer>
        <p>I don't have a footer. This shouldn't even be here.</p>
      </footer>
    </article>
    <aside id="sidebar">
      <h3>Archives</h3>
      <ul>
        <li><a href="">Sooper interesting story.</a></li>
        <li><a href="">Very interesting story.</a></li>
      </ul>
    </aside>
  </section>
  <footer id="footer">
    <p>No rights reserved.</p>
  </footer>
  </body>
</html>

Simple. There isn’t much guesswork involved in deciding which elements to use where. I typed that out without grabbing from an existing project just to make sure I can say this: IT DOES NOT TAKE ANY LONGER THAN CODING IN HTML4 OR XHTML.

BTW, maybe you spotted some seemingly redundant id’s up there. (E.g., <header id="header">) I did too, but I like to keep specificity basic, and we’re allowing for multiple uses of the same elements. I also have some carry-over habits from my time with divs, and, like I mentioned above, I’m not asking you to throw out any of your practices. I’m just suggesting you can enhance them.

Browser Compatibility

You’re right to be concerned about browser compatibility. There is a whole gaggle of browsers that won’t recognize these new elements. We need to declare them in our css:


header, nav, article, section, figure, aside, footer { display: block; }
time { display: inline; }

That won’t be enough. Most of you have probably heard of the HTML5 shiv that lets you style these new elements in IE. Ignore it. Go get modernizr instead. Call it:


<script src="/js/modernizr-1.1.min.js"></script>

Done. You’re using HTML5. Your site is also now jacked in Firefox 2 and Opera 1, but we’re all grown-ups here. You’ll also notice some js targeting issues in IE, so you might want to keep using divs for slideshows and the like. But I hate to even mention these things. Issues will be extremely rare.

Bonus! Progressive CSS

This is going to seem like I’m throwing you for a loop, but stick with me — this is the bonus I promised. Now that you’re using Modernizr, you have browser evaluation for CSS3 features already happening. Take a look at (inspect) your html tag. You’ll see classes for something like 24 new properties such as rgba, borderradius, cssgradient, and fontface.

Let’s focus on the last one.

One of the things holding us back from using @font-face was browser (in)consistency. We could add to the font stack, but we couldn’t modify the characteristics if we had to fall back from a narrow font, for instance, to something wider like websafe Helvetica. Now we can.


@font-face {
font-family: 'Snowflake';
src: url('/fonts/SNOWN___.eot');
src: local('Snowflake Normal'), local('SnowflakeNormal'), 
url('/fonts/SNOWN___.woff') format('woff'), 
url('/fonts/SNOWN___.ttf') format('truetype'), 
url('/fonts/SNOWN___.svg#:SnowflakeNormal') format('svg');
}

h1 {
  font-family:':SnowflakeNormal', Helvetica, Arial, sans-serif;
  font-size:2em;
  font-weight:200;/* this is an attempt to bust ClearType rules */
  }    
  .no-fontface h1 {
    font-family:Helvetica, Arial, sans-serif;
    font-size:1.5em;
  }

The .no-fontface class allows us to specify variations to the characteristics we’ve set if the browser in question can’t handle @font-face. I’m looking at you, FF3.

Sorry to drop all that as an offhand bonus. I realize if you haven’t played with @font-face yet this might seem like a bit to digest. But FontSquirrel is going to let you find free fonts as well as help you bundle them up for use. The @font-face code above (basically) comes from FontSquirrel. If you want to read a bit more, I wrote about it here.

Two disclaimers: 1. You’re going to want to get your font into photoshop / fireworks / whatever prior to build. Trying to find a close match after the fact will make your head explode. 2. You’re going to hate Firefox 3. It won’t support @font-face whatever you do, and your visitors’ browser stats might make you question your use. If this bothers you, fall back to Cufón.

Anyway…

I don’t buy HTML5 not being worth any coder’s time. It’s easy to implement, and it’s scary to think that some of the brightest authors are going to wait for the spec to be finalized before they get in to try it out.

We’ve launched six projects using html5 and @font-face now, by the way, and are about to launch six more. I’d love to hear if any of you are using it as well. Maybe you’re doing it way better than I. I’d love to steal your ideas.