Delivering mobile-friendly styles and markup

patterns & practices Developer Center

On this page: Download:
Goals when developing mobile-friendly markup | Structuring your HTML | Setting the viewport tag | Structuring your CSS - Use flexible values, Consider browser diversity, Consider performance, Create modular, reusable styles | Embracing browser diversity | Knowing when and what to reuse - Reusing markup, Reusing CSS, Reusing JavaScript | Summary Download code samples

Goals when developing mobile-friendly markup

The key to mobile-friendly markup is structure. Mobile browsers are often less powerful than their desktop counterparts. They are often used on resource-constrained devices, and may be subject to latency from both the network and the device. These factors may cause markup, scripts, styles, and images to download and render slowly—or at worst, not at all.

Structuring your HTML

To be mobile friendly, HTML should be simple, clean, and well structured. Delivering well-structured markup speeds parsing and rendering, and will ensure that if images or styles don’t load as planned, there will still be human- and machine-legible markup underneath.

The best way to create mobile-friendly HTML is to keep things simple.

  • Use HTML elements for their intended purpose. If your text is a header, use an appropriate, semantically relevant tag (such as an <h2> or <header>) instead of wrapping it in <div class="header">.
  • Use semantic elements to take advantage of the cascading aspect of CSS.****All browsers that support HTML will include a default style sheet with instructions to render semantic elements defining paragraphs, headers, or text emphasis. There will, however, be no default styling available for random markup enclosed in a <div> element. Taking advantage of a browser’s built-in styles may also enable you to write fewer CSS definitions, which can result in smaller downloads and faster parsing and rendering.
  • Think twice before wrapping semantic elements (such as headers or paragraphs) in an additional div or container. Remember that each new element must still be parsed, and may require additional styles that will increase the size of your style sheet. These elements also often require longer CSS definitions, with increased specificity, which can also increase the time required to parse the styles.
  • Where possible, use the new HTML5 semantic elements (such as header, footer, section, and aside) to further clarify your markup. These elements can be styled and will cascade, like any other HTML element. They are supported on most desktop and smartphone browsers including Windows Internet Explorer starting at version 9. A polyfill script is also available to enable support back to Internet Explorer 7, but should be tested thoroughly to ensure it works on target devices. The HTML5 specification also includes a series of new form attributes and input types. These include input placeholders, built-in form validation for common inputs such as an email address, and attributes that can be set to constrain the input type. These are only supported on newer browsers, but are designed to degrade gracefully and thus can safely be used in your base markup. See Developing mobile-friendly forms for more details.

Setting the viewport tag

Setting the viewport meta tag is an important step when developing mobile-friendly markup. Mobile devices come in all shapes and sizes, but their physical size is just one of three factors that impact the user experience. Each device also has a screen size, measured in hardware pixels, and a pixel density measurement, which is the number of pixels per inch (ppi).

Content on a high-ppi display is small and crisp, as pixels are smaller and more of them have been squeezed onto the screen’s physical space. Conversely, content on a low-ppi display will be larger and fuzzier, as fewer (and larger) pixels have been used to display the content.

This creates an interesting problem. Devices with a high ppi may be quite crisp (which is considered a feature), but the content may be uncomfortably small (which would be considered a bug). Handset manufacturers compensate for this by setting an implicit viewport size. For example, while the Samsung Galaxy S2’s display is 480 x 800 pixels, the viewport has been adjusted to a dimension of 320 x 450 pixels to improve legibility.

It’s important to respect these preset dimensions when developing your app. You can do so by adding a viewport meta tag and setting its content property to a value of "device-width".

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

Doing so instructs the browser to render the page using this preset device viewport width.

Note

While it is possible to change this value, you should consider the implications that such a change will have on the hundreds of devices you might have to support. A value that improves the legibility of your app on one device may decrease the legibility on another.

Other settings are available to control the minimum, maximum, and initial scale at which the page will load. The user-scalable property can also be used to prevent a user from zooming in and out. These should also be used with caution. And as a rule, it’s best to simply let the device choose the most appropriate viewport behavior, and not attempt to control or constrain what the user can do.

Note

Do not forget to include the viewport tag. If a viewport width is not specified (either with a fixed value or a setting of device-width), most mobile browsers will default to a much larger value—often 960px. This will result in a tiny layout that is difficult to read, even if that layout has been mobile optimized.

Please consult The IE Mobile Viewport for Windows Phone for additional details.

Structuring your CSS

Mobile-friendly CSS is lightweight and embraces the inherent flexibility and diversity of the web.

Use flexible values

Where possible, use flexible values such as em units for typography, and percentages for layouts. These keep the layout adaptable and result in a more malleable and future-friendly user interface. They also provide users full control over font size, should that option be available in their browser. Pixel values can, of course, still be used when setting media queries or specifying borders.

Consider browser diversity

Writing CSS for devices requires pragmatism. There are thousands of mobile devices, several rendering engines, many popular mobile browsers, and many versions of each browser. Clearly, understanding the specification level of each browser or device is impossible. It’s therefore important to create CSS that is not specifically dependent on the specifications or characteristics of just one browser.

For example, when specifying advanced CSS styles such as gradients, don’t forget to use all vendor-specific CSS extensions so as not to favor one browser or rendering engine over another. The example below demonstrates the use of vendor-specific extensions when specifying a gradient background.

disabled.button{
background-color:#bec5cc;
background-image:linear-gradient(top, #fcfdfd 25%, #d1d5da 75%);
background-image:-o-linear-gradient(top, #fcfdfd 25%, #d1d5da 75%);
background-image:-moz-linear-gradient(top, #fcfdfd 25%, #d1d5da 75%);
background-image:-webkit-linear-gradient(top, #fcfdfd 25%, #d1d5da 75%);
background-image:-ms-linear-gradient(top, #fcfdfd 25%, #d1d5da 75%);
background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0.25, #fcfdfd), color-stop(0.75, #d1d5da));
-moz-box-shadow:0px 1px 1px #b0b8c1;
-webkit-box-shadow:0px 1px 1px #b0b8c1;
box-shadow:0px 1px 1px #b0b8c1
}

Be sure to test the design using all the specified rendering engines and consider as well what will happen if the feature isn’t supported at all. In the example above, we have specified all gradient vendor prefixes, but have also specified a flat background color, which will be applied in cases where gradients are not supported.

Consider performance

An easy way to improve performance in your app is to reduce the number of HTTP requests. Consider ways to group your style sheets (to reduce the number of requests) but don’t be afraid to keep them separate if this provides efficiency in other areas. Mileage Stats, for example, uses three style sheets. Each style sheet is triggered by a media query breakpoint, but additional media queries have also been placed inside of each style sheet. This media query inside of a media query technique provided us with the ability to layer multiple media query declarations, while reducing the nesting of styles, and keeping the style sheets light and easy to maintain. The benefit of these smaller, more versatile style sheets was in the end far greater than the reduction in latency would have been had we combined them.

Note

Be sure as well to minify and compress (gzip) all style sheets to reduce network transfer and download time.

Create modular, reusable styles

As suggested in Structuring your HTML, the best base for a mobile app is well-structured markup that prioritizes the use of semantic HTML elements over non-semantic elements such as divs. The key benefit of well-structured and semantic markup is that it enables you to reduce the number and complexity of the style declarations you create. This will ultimately impact a style sheet’s file size and the time required to parse and render the content.

The cascading nature of styles allows us to create a common or base style that can be augmented/extended by applying additional styles. This enables us to create modular, and easily extensible components that can be reused throughout the app.

In the example below, we’ve used one generic markup structure to define a basic container for a flash message. The container has no inherent size, so it can be placed anywhere in the app. A 1-em margin has, however, been added around the container to ensure that it doesn’t bump into other elements. The corner has also been surrounded by a 1px border. The paragraph text within the container has also been styled.

<div class="flash">
<p>{{notificationMessage}}</p>
</div>
.flash {
    margin: 1em;
    border: 1px solid #64717D;
}
.flash p {
margin: 0 0 0 .5em;
padding: .7em .5em .5em 2em;
background-repeat: no-repeat;
background-position: center left;
}

JJ149680.09661AC042814E69BE0216B52AEB5279(en-us,PandP.10).png

The unstyled base component as described in the code above

The markup and styles above form the base for a highly reusable component that can easily be modified using an additional class. In the following example, the addition of an alert class inserts a red stop sign icon and changes the container’s border and text color. These changes turn the generic component into an alert message.

<div class="flash alert">
<p>{{notificationMessage}}</p>
</div>
flash.alert {
    background-color: #fff5f3;
    border-color: #d72e02;
}
flash.alert p { 
    color: #d72e02; 
    background-image: red-error-icon.png; 
}

JJ149680.423C29CA5AD5824C9D19C4B1AEA88766(en-us,PandP.10).png

The final set of components used in the app

Modular styles such as these can be enhanced even further using a CSS preprocessor such as LESS or Sass. These tools provide many time-saving (and productivity-boosting) features such as nesting, mixins, and variables. These features can reduce unnecessary markup and style declarations, and simplify refactoring and ongoing maintenance.

The example below shows the combined flash and alert classes, this time demonstrated using Sass syntax.

.flash {
    margin: 1em; 
    border: 1px solid $highlight;
    p {
        margin: 0 0 0 .5em;
        padding: .7em .5em .5em 2em;
        background-repeat: no-repeat;
        background-position: center left;
    }
    &.alert {
        background-color: lighten($alert, 55%);
        border-color: $alert;
        p { color: $alert; background-image: $img-alert; 
    }
}

Embracing browser diversity

A challenge when designing, developing, and testing mobile experiences is accepting that your design will look different from device to device. Understanding how much variety you can expect, and conveying this to your entire team is extremely important. This will enable you to manage stakeholder expectations and avoid spending valuable time discussing, and attempting to debug design differences that you cannot control.

Don’t expect the layout to be pixel perfect on each device. Differences in margin, padding, and alignment may be unavoidable due to differences in each browser’s implementation. If most devices are rendering as expected, it may not be worth expending valuable resources trying to tweak small differences on one or two browsers or devices.

JJ149680.6425DE43CA55B38301A07953D038673A(en-us,PandP.10).png

The New Vehicle form as rendered on an iPhone 4 using the native Safari browser, an iPhone 4 using the Opera Mini browser, and a Nokia Lumia using Internet Explorer 9

Implementing these tweaks may also involve the implementation of browser-specific hacks (often using user-agent sniffing to identify the specific browser variant). Each of these will require testing to ensure they don’t inadvertently impact other devices, and may need to be tweaked, retested, and maintained long-term. This may create a huge amount of overhead for you, while delivering an improvement that is only barely noticeable to the user.

Focus instead on fixing highly noticeable problems that affect legibility, such as text or images that overflow onto other elements, inconsistently sized copy, or elements that disappear off the edge of the page. These larger problems are often easy to replicate on the desktop, and can often be resolved through tweaking or refactoring of markup and styles.

See Styling form elements for recommendations specific to forms.

Tip

Test often during the implementation of styles and layout, and where possible, take screenshots of problems you encounter as you implement key aspects of the design. This will provide a useful reference for your test team and avoid the filing of unnecessary bugs. It will also assist in stakeholder discussions, enabling team members to quickly review and discuss differences in rendering across devices.

Knowing when and what to reuse

When creating a mobile version of an existing app, it’s natural to want to reuse existing code and assets. This can be counterproductive as desktop code, styles, and markup were almost always created with more powerful devices in mind.

Reusing markup

Good mobile markup is simple, to the point (with few extraneous divs or containers), and makes good use of semantic elements. The more complex the markup, the harder the browser will have to work to parse (and if necessary) adapt it. It’s therefore often hard to reuse markup that was created for the desktop, as it may be bloated and overly complex.

Reusing CSS

Existing CSS is also hard to reuse as it may have been created to match your more complex desktop markup. It may also include properties that aren’t supported on mobile browsers, or effects such as CSS gradients, shadows, and transparencies, that can severely impact performance.

Reusing JavaScript

For similar reasons, it may be difficult to reuse existing JavaScript. JavaScript support on mobile devices varies, so you should not assume your code will simply work across all the devices you need to support. You may also want to reconsider the use of JavaScript-based animations, as these are CPU intensive. Creating animations using CSS is less likely to cause performance problems, but may not be as well supported as an equivalent JavaScript animation.

As mobile browsers and devices are incredibly diverse, it’s always important to develop using the principles of progressive enhancement. This includes the use of unobtrusive JavaScript practices and feature detection to ensure that functionality is only implemented when support actually exists. Although these practices are also widely encouraged when developing for desktop computers, it’s possible your app may not have been designed in this way. This may make it difficult to reuse front- and back-end controllers.

See Delivering a responsive layout for additional details on the markup and CSS strategy.

Summary

There are a few points you should keep in mind when aiming for mobile-friendly solutions. First, simple markup is both easier to maintain and faster to load. Second, understanding how the viewport affects the rendering of your markup has a big impact on the experience of your users. Third, CSS is inherently difficult to maintain. Using tools such as Sass or LESS can help to mitigate the difficulty.

Next Topic | Previous Topic | Home | Community

Last built: June 5, 2012