Seeing the world through high DPI

May 21, 2013

At Google I/O this year every attendee got a brand new, beautiful Chromebook Pixel - for many, it was their first high DPI (a so called retina) laptop, and I think many people realized how, um, not so beautiful 1x images look on a 2x screen. In other words, how crappy most of the web looks on a high DPI display.

While there, John Mellor and I gave a talk covering the best practices for building sites that look good on high DPI displays. We covered the theory behind the three different types of pixels and how browsers display 1x images on 2x displays, and the best practices for making sure your site looks great on any device, no matter what if it’s a regular screen or a high DPI display.

You can check out the video below or on YouTube, and we’ve also posted the slides.

  • #Conferences
  • #Web Design
  • #BestPractices
  • #mobile
  • #viewport
  • #io13
  • #highdpi
  • #retina


Viewport target-densitydpi support is being deprecated

February 21, 2013

Support for target-densitydpi in the viewport meta tag was recently removed from WebKit and with Chrome for Android moving forward to current revisions on WebKit, this change is now rolling out in Android. This change affects only a small number of sites because of the limited implementation of the target-densitydpi attribute. It brings Chrome and other WebKit based browsers in compliance with the specification and matches the behavior of other modern mobile browsers.

In order to to best understand what’s changed, you need to remember that a device pixel is not the same as a CSS pixel (see CSS Pixels), and that high DPI displays are able to create crisper and sharper images by fitting more device pixels into a smaller space. This means that in order for content to appear at a normal size, the browser treats each CSS pixel as multiple device pixels and the browser scaled up assets and images to fit within the correct number of CSS pixels.

In Android browser and early versions of Chrome for Android, developers could use target-densitydpi=device-dpi viewport value to force the browser to make a CSS pixel the same size as a device pixel, which may cause content to appear incorrectly scaled on screen (as seen in figure 1).

An Easy, Quick Fix

In most cases, if your site is affected by this change you can fix it easily by serving the same mark-up (including viewport) to Chrome for Android as you serve to mobile Safari (which never supported target-densitydpi).

Best Practices for Modern Mobile Web Sites

When designing a new mobile site, or updating existing pages, you should use modern techniques for dealing with high DPI displays; including always using <meta name="viewport" content="width=device-width"> and a flexible layout for mobile sites. Remember, device sizes, orientations and pixel ratios vary which means that your site may be displayed on a screen ranging from 320 to over 600 CSS pixels wide.

For more information about best practices for building websites that work well on high DPI displays, check out Reda Lemeden’s Towards a Rentina Web article on Smashing Magazine.

One Other Little Note

While writing up this post, I accidentally did a search for sites that used target-density instead of target-densitydpi and I came across quite a few of them. If you’re using target-density (without the dpi at the end), you can just remove it, it wasn’t doing anything!

  • #Web Design
  • #HTML5
  • #BestPractices
  • #mobile
  • #viewport
  • #target-densitydpi


Meta viewport syntax - comma or semi-colon?

February 14, 2013

TL;DR: If you’re using a semi-colon to separate values in your viewport meta tag, your site may break! Use a comma instead.

Browsers can be pretty forgiving most days, they do their best to fix our coding mistakes; but it’s a tough job. Most days, they manage to get it right, but trying to fix all the possible error cases is pretty hard. Worse yet, sometimes one browser fixes our code for us, while others don’t.

The viewport meta tag seems to be one of those elements that’s a little bit persnickety. The CSS Device Adaptation spec says the correct syntax uses a comma to separate the values. Unfortunately some sites use a semi-colon, which causes the browser to ignore your viewport settings completely!

Correct Syntax

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

Incorrect Syntax

<meta name="viewport" content=width="device-width; initial-scale=1.0" />

If you want to see this in action and how bad things can look, use the remote debugger with Chrome for Android Beta to change the comma to a semi-colon in the viewport meta tag on Google.com. The site will suddenly go from looking good, to looking awful.

The Developer Tools also warn you in the Console when it comes across an invalid viewport meta tag with the warning: Viewport argument value "device-width;" for key "width" is invalid, and has been ignored. Note that ';' is not a separator in viewport values. The list should be comma-separated.

Go make awesome, but use a comma!

  • #HTML5
  • #TipsAndTricks
  • #BestPractices
  • #mobile
  • #viewport


Using meta viewport

December 12, 2012

Using meta viewport to optimize rendering on mobile devices

What is the viewport?

Imagine if every web page you opened on your phone or tablet got the same version as your desktop, and was displayed on the small screen of your device. On a phone, that might mean you would see only the top leftmost corner, a tiny 320px by 480px view, and you’d have to scroll around the page to be able to see everything. (See figure 1). Unlike a desktop or laptop, there is no way to resize the browser window to fit the content that you want to see. Thankfully, on mobile devices, almost every modern browser scales and renders the page so that you can more easily see and interact with it, panning and zooming into the areas you’re most interested in.

Most mobile browsers define a default viewport width of 980px CSS pixels, meaning that they lay out the page on a 980px wide area, then scale it down to fit within the width of the screen. (If you’re unfamiliar with CSS pixels, device pixels, device pixels ratios, or the like, check out the Smashing Magazine article Towards a Retina Web. This works great for most desktop sites that don’t take into account mobile devices and were designed for big screens. Sites that were designed to be compatible with narrow screens however are likely to be unnecessarily stretched and scaled. For example, see figure 2 - there is no viewport set, and the image is 1600px wide, that means users need to scroll left to right to see all of the content.

The meta viewport tag allows you to override the browser default value, allowing you to adjust the display and zoom level to best suit your web page.

Using meta viewport

Setting a specific viewport width

To override the default viewport defined by the browser you simply need to add a viewport meta tag in the <head> section of your page:

<meta name="viewport" content="width=320" />

Setting the viewport width to 320px, is similar to resizing your laptop browser window to be 320px wide, now the browser will render the page on a canvas that’s 320px wide. If your device is 320px, then you’re all set, the browser doesn’t have to do any scaling and you’re pretty much all set. Obviously not all devices are 320px wide, and your site most likely isn’t 320px wide.

But what happens if you rotate the phone from portrait to landscape, and suddenly the device is now actually 480px wide? If this happens, the browser scales the content up by 50%, so that the 320px width, so that the 320px wide document is stretched to fit in the 480px wide browser window. Unfortunately, when this scaling is applied, less content will be displayed above the fold, and the content may look oversized.

If you’ve designed a site for a fixed width desktop, for example, you know your page is 600px wide, then you can simply add <meta name="viewport" content="width=600" /> to the <head> of your document, which will scale the content to fit within the window. Depending on the density of your content, this may work well, but you’ll want to test it to make sure.

Adding a specific width viewport, is discouraged unless you’re adding it to a legacy site as a stop-gap measure until you can build a more responsive site.

Setting the viewport width to the device-width

Consider the sustainability of a fixed width website and how it would look given the huge variety of mobile web devices, each with a different screen size, it becomes even more of a challenge when those devices are used in landscape mode. For that reason, building your site using a responsive approach and placing it within the viewport without any zooming will help to make your site look great across all of those devices. It doesn’t need to be responsive from phone all the way to desktop, but it should at least flex from a small portrait phone, to a mid-sized mobile tablet in landscape; about 320px to 640px.

When you design your page or web app using a responsive approach, you don’t want the browser to render your responsive content in a viewport that is 980px wide and then scaled down to the tiny screen; instead you want the content to render in the actual viewport size. To do that, you can tell the browser to set the viewport to be the width of the actual device by applying the following meta viewport tag:

<meta name="viewport" content="width=device-width" />

This means the viewport will be proportional to the width of the device’s screen, for example on any portrait iPhone (whether or not it is retina) the width would be 320 CSS pixels, on a landscape iPhone 3 or iPhone 4 it would be 480 CSS pixels, on a portrait Nexus 4 it would be 384 CSS pixels, and on a landscape Nexus 4 it would be 640 CSS pixels

Setting the viewport scale

When you specify a specific value for the viewport width, the browser will automatically determine the appropriate scale factor needed. For example, if you set the width=640 on a device that has a screen width of 320px, the browser will scale the content by 0.5.

In some cases, you may want to specify the scale used by the browser. You can do this by setting initial-scale, minimum-scale and maximum-scale.

<meta name="viewport" content="width=device-width, initial-scale=1">

Initial scale forces the browser to an initial scale, but still allows the user to pinch-zoom on the content to be able to make things larger or smaller. By using minimum-scale or maximum-scale, you can set a boundary on the amount of scaling the user can do.

You can also prevent zooming by adding user-scalable=no, or setting the minimum-scale and maximum-scale to the same values. This is particularly useful for mobile web applications where it doesn’t make sense to allow the user to zoom or scale content.

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">

Currently the user-scalable property does not work in Chrome for Android (m18).

Setting the viewport height

In addition to setting the viewport width, you can also set the viewport height. While it’s not something that’s used often, it’s good for mobile web applications that may pan horizontally only.

<meta name="viewport" content="height=device-height">
  • Adding a specific width viewport, is discouraged unless you’re adding it to a legacy site as a stop-gap measure until you can build a more responsive site (you’ll need to replace the 320 with the width of your site): <meta name="viewport" content="width=320" />
  • The viewport property target-densitydpi has been removed from the CSS Device Adaptation specification and should not be used. It has been deprecated in Chrome for Android, and has never been supported in Mobile Safari or Firefox for Android. For more information, see Mozilla Bug 797090 or WebKit bug 88047.

Best practice for using meta viewport

  • Use a comma to delimit different viewport properties. Although semi-colons may work, they do not behave consistently across browsers.
  • For a responsive website, designed with mobile in mind and where the user may want to be able to zoom in to particular areas of content:
<meta name="viewport" content="width=device-width, initial-scale=1">
  • For a mobile web application where you don’t want to allow zooming of the content:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">

The Future

Currently, the only consistent way to specify the viewport for a page is via the meta viewport tag, but the W3C is currently working on a CSS Device Adaptation, that will provide a way to specify the size, zoom factor and orientation of the viewport in CSS using the @viewport rule. As of late 2012, only Opera Mobile 11+ and Internet Explorer 10 provide support for it using a vendor prefix.

Additional Resources

  • #Web Design
  • #CodeSample
  • #HTML5
  • #HowTo
  • #TipsAndTricks
  • #Multiple Browsers
  • #BestPractices
  • #Web App
  • #mobile
  • #viewport
  • #chrome


Thinking about the offline web

April 17, 2012

Over the last few months, I’ve spent a lot of time thinking about how to make it easier for developers to build web applications that work offline, its a tough problem to solve. The web has the features/technology to do it, but I think there are two things preventing us from getting there easily. The first is a perception issue for users, many people think that the web only works when they’re online, no internet, no web. That leads to a bit of a catch-22, users aren’t asking for it, so developers aren’t prioritizing it. The second problem is that it requires a change in the way we build web applications. Instead of building server side web applications, we need to build more client side web applications that use web-based APIs to get what they need.

More than just ‘offline’

But applications that work offline isn’t the only reason to start using these new techniques. There are lots of other scenarios that benefit from the offline experience. For example, the intermittent connection where someone may have a connection for 5 minutes, then lose it for 2 then have it again for 3 minutes. The low bandwidth connection, for people connected maybe by dial-up or 3G modem. It also benefits the person with a great net connection - because any time you load data from the local machine, it’s almost guaranteed to be faster than if it were to come across the network. The performance benefits are pretty significant here!

Reuse the same code for different platforms

If you’re already building native (iOS, Android, Desktop) applications, you probably already have the set of server-side APIs, build your web application to take advantage of those to get the data that it needs. Architect your web application in the same way that you’re building native applications - using the same set of APIs and XMLHTTPRequests! If you’re worried about performance (and everyone should be), you should cache data locally, so that after the first time the app is run, it only needs to get the newest data from the server, and there is some available immediately at start up.

Offline techniques

Building applications that work offline requires two main things, a way to store the applications components (the HTML, JavaScript, CSS, images, and other assets) on the user’s machine, and some way to store data. Solving the first problem is done with the HTML5 feature application cache, which tells the browser to explicitly store the necessary files locally on the user’s computer, and instead of asking for them from the server every time, load them from the cache.

HTML5 offers lots of great ways to cache data locally, localStorage, indexed DB and web SQL. Unfortunately, the only consistently available storage feature today is localStorage, but it’s got a few drawbacks. WebSQL works across most browsers, but it has been deprecated, and could go away at some point. The recommended method, is indexed DB, but it’s not available in all browsers yet, but it’s coming. Check out http://caniuse.com for more info about implementation.

Up next - how do we get users to demand offline?

  • #Performance
  • #Fast
  • #BestPractices
  • #AppCache
  • #offline
  • #indexed db