CSS best practices

In this section, we'll provide some tips and best practices for your stylesheets.

Use efficient CSS selectors

To create an efficient web application, you should understand how a browser reads your web pages and renders them. When a browser reads your HTML document, it parses the HTML elements and assembles them into a document tree. The browser then matches the elements to the style rules that you specified in your stylesheets. The browser reads your style rule from right to left, starting from the rightmost selector, called the key selector, and moving left through each additional selector, or descendant selector, until it finds a match or discards the style rule. To make this matching efficient, you need to decrease the time it takes for the browser to find a matching style rule.

Consider the following example:

#home a {color: blue;}

We'd expect to read this selector as: find the element with the id="home", then apply the color style to every anchor (<a> tag) it contains. You might think this would be quick because we are using an ID tag and ID selectors are typically fast. However, because the browser reads the selectors from right to left, here's how the browser actually reads the rule: find every anchor tag, then check that its parent element has an id="home", keep checking until a match is found or until the end of the HTML document is reached.

A more efficient way to write this style is to avoid the descendant selector and use a class that's associated with the anchor tag, such as:

.home-anchor {color: blue;} 

So, the idea is to write more specific style rules so that the browser spends less time looking to match your style.

#main-navigation {   }      /* ID (Fastest) */
body.home #page-wrap {   }  /* ID */
.main-navigation {   }      /* Class */
ul li a.current {   }       /* Class *
ul {   }                    /* Tag */
ul li a {  }                /* Tag */
* {   }                     /* Universal (Slowest) */
#content [title='home']     /* Universal */

Although there might be a performance benefit in using appropriate CSS selectors, you shouldn't take the selector rules too far because you might see a disproportionate increase in maintenance costs vs. the performance benefits you gain. As always, you should analyze the performance of your application by using the Web Inspector. For more information about the Web Inspector, see Debugging using Web Inspector.

There are four types of selectors. ID and class selectors are more efficient than tag or universal selectors.

Selector Description
ID

This selector matches the unique element in the page with the specified ID.

Example: #chapter1 {text-align: center; }

Class

This selector matches all elements with a class attribute contain the class name.

Example: .chapter1 { font-weight: bold; }

Tag or type

This selector matches every instance of the element type in the document tree.

Example: h1 { font-family: sans-serif; }

Universal

This selector, written using *, matches every element in the document.

Example: * {font-family: Arial; }

The following example shows where a class selector would be more efficient that a descendant selector:

Slower

ul li {color: blue;}
ol li {color: red;}

Faster

.unordered-list-item {color: blue;}
.ordered-list-item {color: red;}

Specify image dimensions

To improve the rendering speed of your web page, if your page has embedded images, it's a good practice to specify the dimensions of your image.

<img src="img/logo.png" style="width: 100px; height: 100px;">

Because a browser downloads each image separately, it helps the browser to know the image's height and width. This allows the browser to create an appropriately sized placeholder so it can determine the page layout while the image downloads. Otherwise, the browser has to reflow the page after each image downloads and the image's real size becomes known. This slows the rendering of the page and negatively affects the user experience.

When you specify the dimensions of the image, it should be the actual image size. Do not scale images on the fly by specifying a different width/height than the actual image. For example, say an image file is actually 50 x 50 pixels, but you want the image to display smaller, so you set the dimensions to 20 x 20 pixels in the HTML. Rescaling images consumes CPU cycles, causes repainting which uses more memory, and slows page rendering.

Instead, create your images at the appropriate size. This will not only improve rendering speed, but also avoid downloading an unnecessarily large file. Remember that most mobile data plans are not unlimited, so you want to reduce the data usage for the user.

To set an image's size, you can use the width and height attributes of the <img> tag or the width and height CSS properties. There is no need to use both because CSS properties override HTML attributes.

Examples

HTML

<img id="logo" src="logo.jpg" alt="Company logo" height="100" width="100" /> 

Inline CSS

<img id="logo" src="logo.jpg" style="width: 100px; height: 100px;">

External CSS

#logo { width: 100px; height: 100px; }

Use CSS sprites

You can reduce the number of HTTP requests for images on your web page by using CSS sprites. The CSS sprites technique allows you to combine all your background images into one large image and use background positions to show or hide a portion of that image in an HTML element. Not only does this technique reduce load times but it also provides cleaner markup and cleaner projects (fewer image files to manage). CSS sprites can be used in many ways but it's ideal for rollover buttons and navigation menus.



Here's an example that uses the nth-child notation along with CSS sprites to create a navigation menu:

#navcontainer li {
    background-image: url('spritebg.jpg'); /* single image */
}
#navcontainer ul li:nth-child(1) {
    background-position: -130px -700px; /* position = xpos ypos */
}
#navcontainer ul li:nth-child(2) {
    background-position: -130px -718px;
}
#navcontainer a {
    width: 250px; /* size */
    height: 18px;
}

Trigger hardware acceleration

If you are using animations in your application, you can improve the user experience for your app and create smooth transitions by triggering hardware acceleration. By default, most browsers do not have hardware acceleration turned on. The browser typically uses hardware acceleration for elements that would benefit from it (for example, WebGL components, transitions, and 3D transformations). However, if you want a specific element to benefit from hardware acceleration, you can manually trigger hardware acceleration on that element by adding the -webkit-transform property to your element.

... {
    -webkit-transform: <transform function>;
}

The transform property applies a 2D or 3D transformation to an element. You can use the transform property to rotate, scale, skew, and translate elements.

In the following example, we animate an image by using the transform property and applying a 15 degree rotation around the Z and Y axis.

img.rotate3d {
    -webkit-transition: -webkit-transform 1s ease-in-out;
    -webkit-transform: rotate3d(0, 0, 1, 0deg);
}
      
img.rotate3d:hover {
    -webkit-transform: rotate3d(0, 0, 1, 15deg);
}

Keep in mind that triggering hardware acceleration doesn't mean you'll have a faster app. An element with a 3D transform applied to it (or other hardware-accelerated elements) is painted into GPU memory so that it can take advantage of accelerated transforms. This technique does not speed up the cascade, layout, JavaScript, or the painting of anything, it simply speeds up the transform.

Important: You should use this technique sparingly! The GPU is not shy about using resources, including battery power and memory.

Optimize scrolling performance

Hardware acceleration can also improve a user's interaction with any scrolling content in your app, such as lists or grids. By default, the overflow CSS property is not hardware-accelerated, and using it on a list that contains a lot of content can result in performance issues, such as sluggish scrolling or an inconsistent response to touch input.

To benefit from hardware acceleration, include the -webkit-overflow-scrolling: touch property if you use an overflow property in your app. Here's an example:

... {
    overflow-x: scroll;
    -webkit-overflow-scrolling: touch;
}

When you make this addition, it allows for momentum and smoother scrolling, a visual bounce effect when the user reaches the top or bottom of the list, and a more responsive touch interaction.

Last modified: 2014-03-10



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus