Scott Hanselman

Learning about Progressive Enhancement - Supporting Mobile Browsers with CSS3 Media Queries

August 25, '11 Comments [32] Posted in ASP.NET | ASP.NET MVC | Javascript | Mobile
Sponsored By

This site on an iPhone 4This site on a Windows Phone 7 MangoI blogged about how happy I've been working with designer Jeremy Kratz on my recent site redesign. We've been meeting lately about small improvements and tweaks. One of the core goals was to support many screen sizes from 30" down to a small smart phone screen. You can see the results on the right in a Windows Phone and iPhone.

My team is doing a lot of work on Mobile lately, not just with things like jQuery Mobile and what that means not just for ASP.NET but the mobile web in general. We've also worked with 51Degrees and they've even created a NuGet package that can help you tailor your site to any device. You'll hear more about Mobile in ASP.NET from Steve soon and I'll be sharing some ideas in a few upcoming conferences.

I originally enabled this blog for mobile browsing this same week in 2006. That's 5 years ago, when mobile was really just getting started. Back then, I had a separate mobile view that was stripped down and emitted totally different markup based on user-agent sniffing. This was pretty innovative for the time, a half decade ago. There's a number of things in ASP.NET 2 (what this blog runs on) that do adaptive markup. However, more modern techniques use a combination of detecting capabilities on the server side with feature detection on the client. We query the browser with JavaScript: Do you support Geo-Location natively? No? How about using this shim JavaScript library?

When laying out a page, rather than serving up different markup on the server based on the server-detected browser, we can also use CSS3 media queries that modify a layout based on screen (viewport) size. I wanted to use these techniques for this blog.

While I realize that some people want a totally custom iPhone web application when they visit a site, I draw a specific line between a Web Site, a Mobile Web Site and a Mobile Web Browser Application. When visiting what I consider a regular web site, I don't want an iOS-specific Web version and a Regular Web I can't see. What I'd like to see is the site I went to, perhaps with alternative elements or a few things moved around.

However, if the site is full of interactivity, I might want a Mobile Web Site served up with different - perhaps device-specific - markup for different Smart Phones. I think the decision point for how application-like, and therefore device-specific, your mobile website should be hinges on how much your user will be interacting with it vs. just reading/consuming content.

With this blog, there's not a lot that needs to be smart phone specific. I want a mobile-optimized version of the site, not a complete iOS (or Android, or WP7  or whatever) re-imagination of the site. If I did, I'd download an app.

If you're creating a Web Application that focuses on "producing" (meaning pushing buttons, doing application stuff) I can see using a phone-specific framework, but when "consuming" content, I'd like my Web Site to look like a Web Site.

CSS3 Media Queries

Designer Jeremy and I (mostly him!) came up with a goal to support desktops, tablets and netbooks around 1024 pixels wide, and phones less than or around 720 pixels wide.

Here's the general structure of the CSS. Note that none of this is JavaScript. This is all just descriptive "when the screen is like this, apply these styles" stuff.

/* psuedo CSS, not complete */

/* CSS Reset from http://meyerweb.com/eric/tools/css/reset/

Goes here
*/

/* Global Styles for the Desktop Site */


/* Force the images to resize smaller
when they get squished with small screens */
img
{
width: auto !important;
height: auto !important;
max-width: 100%;
}

/* bunch of styles */

/* Hide the dropdown we'll use for
navigation when we are tiny */
#nav select
{
display: none;
}

/* Tablet device styles */

@media screen and (max-width:1024px)
{
/* hide stuff, make things smaller, yank the right rail */
#sidebar
{
display: none;
}
/* hide other stuff */
}


/* Phone device styles */

@media screen and (max-width:720px)
{
/* hide the huge top nav and show the nav dropdown */
}

Desktop vs. Mobile Site Navigation

Everything looks nice, until you resize the site and the top navigation bar really got squished, then overflowed. However, Jeremy had a great idea. The navigation at the top is nice, but when the screen is REALLY small the navigation is overwhelming. The navigation is just an unordered list like this:

<div id="nav">
<ul id="primarynav">
<li id="nav-info"><strong>Info</strong>
<ul>
<li><a title="Learn more about Scott Hanselman" href="http://www.hanselman.com/blog/AboutMe.aspx">About Me</a></li>
<li><a title="Contact Scott Hanselman" href="http://www.hanselman.com/blog/contact.html">Contact Me</a></li>
</ul>
</li>
<ul>
...more..
</div>

Why not show that as a dropdown for tiny screens? There's actually a StackOverflow question on that (did you know Jeremy did the initial StackOverflow design?) I could certainly just put a dropdown in a DIV and hard code it, but since the structure already exists in a UL and I might want to change it in the future as well as avoid duplication, we'll use JavaScript to inject the SELECT into the HTML DOM (Document Object Model).

Basically we just spin through the UL structure and create the select, options and (bonus!) option group using the existing hierarchy.

$(document).ready(function() {
var markUp = ["<select id='primarynav-select'>"], $li, $a;
markUp.push("<option value='' selected='selected'>Go to...</option>");
$("#primarynav > li").each(function(){
$li = $(this);
if($li.find("li").length){
markUp.push("<optgroup label='"+$li.find("strong").text()+"'>");
$li.find("li").each(function(){
$a = $(this).find("a");
markUp.push("<option value='"+$a.attr("href")+"'>"+$a.text()+"</option>")
});
markUp.push("</optgroup>");
}
else{
$a = $li.find("a");
markUp.push("<option value='"+$a.attr("href")+"'>"+$a.text()+"</option>")
}
});
markUp.push("</select>");

$("#primarynav").after(markUp.join(''));
$("#primarynav-select").change(function(){ window.location = $(this).val(); });
});

So this,

The navigation menu as a UL

becomes this, when you resize the browser really small, just by hiding the one and showing the other using the CSS above.

The UL Navigation menu as a Select Dropdown box

Resizing Images for Small Screens

For an important site that gets a lot of mobile traffic, you would want to use a browser database like 51Degrees that could tell you the size of the screen of a specific phone and the graphics formats (PNG, JPG, transparency or not) so you could resize large images on the server side and return mobile-optimized images. You could have a handler that detects small phones with small screens then resizes and caches images. Perhaps even grayscales them for non-color phones.

In my case, my images aren't that large and it's not that important to me to do server-side resizing. Instead we decided to have the images resized on the client side using CSS like this:

img
{
width: auto !important;
height: auto !important;
max-width: 100%;
}

This says, no matter what other CSS or the markup says, it's important that images resize to 100% but no larger. This was a nice simple solution for those larger photos that I put at the top of each post. Rather than overflowing and clipping against the edge of the phone, then resize. You can see this in action by just resizing your browser.

Here you can see this site on an IPad. Note the right rail has disappeared. On the right, the same post on an iPhone 4 which is 640px wide. See how the image has moved up and is the width of the phone?

This site on an iPad  This site on an iPhone 

You can even use CSS Media Queries, without any JavaScript, to detect iPad orientation, or if the user has an iPhone 4 with high-res retina display vs. a low-res iPhone 3G.

Here's example CSS from Web Designer Wall, credited to Thomas Maier and Cloud Four respectively.

<!-- Detect iPhone4 Retina Display from CSS -->
<link rel="stylesheet" media="only screen and (-webkit-min-device-pixel-ratio: 2)" type="text/css" href="iphone4.css" />

<!-- Detect iPad and iPad orientation -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">
<link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css">

You can actually test and simulator the orientations locally by making your desktop browser wider than it is tall.

There's still a few things left to tweak, and these techniques only work with modern Smart Phone browsers that support these features, but for the 8% of you who are reading this blog on a mobile device it should be a better experience now.

One Caveat - Code Samples

As with all nice things, there is one bad thing. The code samples that I have use SyntaxHighlighter. It takes a <pre> and using JavaScript does a lot of work on them, effectively replacing the PRE in the DOM with a bunch of stuff. This looks lovely in a desktop browser and crappy on mobile. I'm still exploring how to fix this. Here's some ideas I have.

  • Conditionally override the SyntaxHlighter CSS using Media Queries
  • Change the plugin to keep the <pre> around, but hidden. Then swap the highlighted one with the plain one on phones
  • Come up with better CSS all up for the highlighter

I'm interested in your thoughts!

UPDATE: I'm currently reading Adaptive Web Design: Crafting Rich Experiences with Progressive Enhancement as it's amazing. Aaron gave me a review copy to check out. He outlines a similar UL to SELECT enhancement and a dozen others in a clear, clean readable manner. I'm enjoy it thoroughly.

Related LInks

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Thursday, August 25, 2011 8:39:47 AM UTC
Site is excellent on iPhone. Job well done.
Thursday, August 25, 2011 8:57:04 AM UTC
Looks great on my Android, except for the fact that the long lines in your code samples expands the page, making the top menu about five screens wide and large images take more space than the screen (since 100% is now five times the screen width). The Android browser nicely reflows the text to fit one screen width though.
Thursday, August 25, 2011 11:22:55 AM UTC
string concatenation with an array as a StringBuilder is a neat trick. Might worth commenting about it though for people not familiar with the technique.

as for the code samples - with my iphone4 they look great. you can scroll with two fingers. A distinct background or border would make it clearer that it is a separate, scrollable area
Thursday, August 25, 2011 12:36:01 PM UTC
Was this tested on a WP7, pre-mango? I'm using my Samsung Focus and the site CSS is jumbled...
Thursday, August 25, 2011 12:57:27 PM UTC
+ 1 on code sample width mentioned above. A wrap at about 40 chars might do the trick.
Joshka
Thursday, August 25, 2011 12:59:39 PM UTC
Also theheader and footer don't seem to shrink on android (dolphin nd)
Joshka
Thursday, August 25, 2011 1:11:59 PM UTC
Oh how it pains me to say it, but it looks awful on WP7 NoDo.

Mango is close enough that going this route is the best (only) choice overall, but ding dong dang it how annoying that sites look so much better on Android and iPhone (and WebOS!).

If Mango did nothing but smite IE 7++ with a +5 Mace Of Mango-y Justice and obliterate it from WP7, then Mango would be a hugely worth-while upgrade...

In fact if I were Emperor Of The Known Universe, I would require Microsoft to include a WebKit based browser on WP7 FOR THEIR OWN GOOD. Even if they keep IE. I would be fine with two browsers on my device if one of them worked well...

My HTC Trophy is my favorite phone so far, except for the browser (and browser control for Silverlight). That and multi-tasking. (No, this isn't going to descend into the Monty Python skit about the Inquisition.)

I certainly plan to use these techniques (awesome work, by the way) in my own development and impatiently await the release version of Mango.
Thursday, August 25, 2011 1:45:10 PM UTC
Yes, Media Query that was the thing that I mentioned you when you posted http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx.

May be you should check 320 and up of Andy Clarke http://stuffandnonsense.co.uk/projects/320andup/ it is nice boilerplate for creating different versions of your site.

Maybe the next thing you should care to make the markup a bit more manageable.
Thursday, August 25, 2011 2:24:32 PM UTC
Great job Scott! I love the simplicity. We've been utilizing CSS3 queries for some of our mobile websites. Incidentally, I'd LOVE your feedback on our site and the concept if you wouldn't mind taking a look...we're launching end of week :)
Thursday, August 25, 2011 3:30:19 PM UTC
This is not what I can see with my Sony Mini Pro. I got the desktop site layout, not the mobile one (and I'm using CyanogenMod)
Exasperant
Thursday, August 25, 2011 3:45:56 PM UTC
I'm with Jeff - I'd love to help you with your Windows Phone view stats...but I'll have to wait until the guys at T-Mobile get around to installing that update disk that the guys at Microsoft sent them for WP7. ;-)

But overall, very cool post. I'm needing to implement these types of tricks in our new site at work too.
Thursday, August 25, 2011 3:48:15 PM UTC
I started using the CSS ideas found at http://csswizardry.com/inuitcss/ on one of my sites. A simple META tag in the HEAD section and then the CSS does the rest. I was absolutely stunned that a layout on my desktop flowed to a very nice layout on my Droid X. I too have been using sniffing and alternate layouts. Now I don't have to! I like what you are doing with images here and will incorporate that in as I learn more CSS3. Thanks!
Thursday, August 25, 2011 4:05:12 PM UTC
Nicely done. Looks good on my Blackberry Bold 9900. Even the code samples look good, though they need to be horizontally scrolled.
Thursday, August 25, 2011 4:39:41 PM UTC
Yeah, sadly it looks awful on WP7. The left 1/4 of the screen is the article body the right 3/4 is either the big header or blank once you scroll down to see the post.
Thursday, August 25, 2011 4:41:54 PM UTC
It'll look great when WP7 updates to Mango and IE9.
Thursday, August 25, 2011 6:29:48 PM UTC
No doubt about it on the Mango front. SERIOUSLY looking forward to the upgraded browser.

As I said earlier, it wouldn't make sense to compromise going forward to look good on a browser with a shelf life of <please insert official Mango OTA update date - today's date here>.

Just wishing the browser upgrade could have come sooner, or we had additional browser choices on the device.
Thursday, August 25, 2011 7:52:55 PM UTC
Scott,
The page looks nice, but it is painful to wait until it loads on an iPhone, even on a wifi.

Do you really need to show all those avatars in the comments. 150 http requests is little extreme, even on a desktop.

If you can reduce the requests and minimize the onload JavaScript, the page will download and render much faster.

If you create the navigation select on the server, instead of with JavaScript will help.

The Microsoft approach of including tons of static content, just in case, is not very effective on mobile devices :)
Thursday, August 25, 2011 9:12:37 PM UTC
Hm....I just loaded it on my iPhone over 3g and it was about 7 seconds. I'm surprised you're seeing it slow on WiFi?

Also, the gravatars are async and cached.

I'll run YSlow and see what I can do to speed things up.

Scott
Thursday, August 25, 2011 10:32:30 PM UTC
Looks bad on WP7. I hope when Mango comes(not sure when) it will look like what u have shown.
Friday, August 26, 2011 12:30:56 AM UTC
I really like the ideas here and I'm going to try them out myself, but I'm curious about the pros and cons of this approach with regards to the size of the response you send.

If you're using CSS to hide elements (like the big top nav) for mobile devices, that means you're still shipping the markup for that section across the internet to the user's device. For things like the top nav isn't it possible to just omit that section completely if you know that the user-agent or the user-agent capabilities are those of a mobile device?
Friday, August 26, 2011 12:44:07 AM UTC
Vikram - It'll look good on IE9/Mango.

Adam - Potentially, but we're talking about less than 1k of markup.
Friday, August 26, 2011 7:38:34 AM UTC
I notice the W7P shows a bit more site per screen.
Friday, August 26, 2011 9:41:14 AM UTC
Scott, for pre tags, look at this post. Worked for me.
Friday, August 26, 2011 3:59:20 PM UTC
Thanks for the write-up. I actually documented the UL to SELECT conversion in my book (Adaptive Web Design) too—in addition to a bunch of other progressive enhancement concepts and techniques.

Great work!
Friday, August 26, 2011 5:56:59 PM UTC
Update: confirming that the site works and looks great on mango beta 2! Nice job.

Now I'm ready to dig into these mobile formatting tips.
Saturday, August 27, 2011 4:46:11 PM UTC
Hi Scott,

This is my first comment on your blog :p

I come here everyday and i wanted to say that i never found an interesting blog like yours.

The power of your blog is the way you share different subjects (tech, life, ...). It's really attractive.

So ... Today i just want to share my feedback about your new blog layout on mobile.

Few days ago, it was ok (nothing to say) but now i've a scrollbar at the bottom for each post and it's annoying.

Did i say that i'm using the Samsung Galaxy S2 defaut browser ?

I don't know how i can help to give you more details but i'm sure there is a solution :p

Keep up the good work !

Regards,
Monday, August 29, 2011 9:17:41 PM UTC
I can attest to the fact that it looks great on a Mango WP7 device. At first, not so good. Now, well done guys! Excellent use of media queries.
Monday, September 05, 2011 8:19:49 AM UTC
When I first time open the site in my android phone interal browser with Android agent, it shows me a dropdown box with "Go to..." inside. but a few minutes later, maybe the page loading finished, it turn to a normal page like I got in my PC browser IE8/Chrome12.
Thursday, September 08, 2011 3:10:42 PM UTC
Hi Scott - great work on this site & thanks for sharing the cool technical details.

How are you testing this site for different browsers & devices?

Thanks,

Navin
Wednesday, October 05, 2011 2:19:23 PM UTC
Hi Scott,

first of all great work on this site and tanks for sharing your knowledge with us.

This might be a kind of stupid question, but... which WP7 phone is that in the picture?
Saturday, October 29, 2011 2:11:23 PM UTC
Sir, hope you don't mind but I am cheating a little bit from this article for my new blog design :)

It is going pretty so far ;)
Wednesday, January 04, 2012 7:13:27 PM UTC
You ever find a satisfying solution for your source code?
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.