December 15, 2009

Using CSS Sprites to save effort and web storage

Yes, I know that CSS Sprites it’s an old technic and you probably know about it. But I still see many people using a single image to do a mouseover effect or even two separated images, which is not wrong. But, you consume more storage and bandwidth from your hosting service, and effort to create several images. If you use CSS Sprites you will also increase your site’s performance by reducing HTTP requests.

What is CSS Sprites

If you already know what is CSS Sprites, jump to the next subject.

CSS Sprites is a technic to reduce HTTP requests, save web storage and increase your web site’s performance by grouping all the significant images into a single one. Using the CSS Background positioning it’s possible to arrange the image so only one is shown when necessary. Is it still cloudy? Check out some images below that represent CSS Sprite usage:

CSS Sprites

The sprite images above are from Google’s new layout and Amazon. They both using CSS Background positioning using only one image. There are lots of other companies using sprites like Yahoo!, AOL.com, Facebook and others.

Getting start with CSS Sprites

Now that you had an overview about CSS Sprites, it is time to get your hand dirty. There are two ways to work with sprites:

  1. Combine all similar images into one (icons, backgrounds, navigation items, buttons).
  2. Create a single image for the entire web site.

I strong recommend, if you never did CSS Sprites, to start with the first way. But, if you a web site like mine, with few images, you can gather all of them into one. For this post, I’ll use the Google’s sprite image.

Creating a web site using CSS Sprites

It’s easy and fast to create your CSS rules using sprite images. Let’s create a simple clone of Google’s result page so we can take all of the items on the image.

Step 1: HTML structure

First of all we need a HTML structure to work on. Here is a simple HTML I did to use as an example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
  <title>CSS Sprite &bull; Step 1 &ndash; Eugenio Grigolon http://eugen.io/</title>
  <link rel="stylesheet" href="reset.css" type="text/css" media="screen" />
</head>
<body>
  <div class="header">
    <h1>Google</h1>
    <input type="text" value="google" /> <input type="submit" value="Search" class="btn_search" />
  </div>

  <h2><a href="#"><strong>Google</strong></a></h2>
  <p>Enables users to search the Web, Usenet, and images. Features include PageRank, caching and translation of results, and an option to find similar pages.</p>
  <p class="url">www.<strong>google</strong>.com
    <a href="#" class="comment">Comment</a>
    <a href="#" class="promote">Promote</a>
    <a href="#" class="remove">Remove</a>
  </p>

  <h2><a href="#">Gmail: Email from <strong>Google</strong></a></h2>
  <p>A <strong>Google</strong> approach to email. Gmail is built on the idea that email can be ... Keep unwanted messages out of your inbox with Google's innovative technology.</p>
  <p class="url">mail.<strong>google</strong>.com
    <a href="#" class="comment">Comment</a>
    <a href="#" class="promote">Promote</a>
    <a href="#" class="remove">Remove</a>
  </p>

  <h2><a href="#"><strong>Google</strong> Videos</a></h2>
  <p>Search and watch millions of videos. Includes forum and personalized recommendations.</p>
  <p class="url">video.<strong>google</strong>.com
    <a href="#" class="comment">Comment</a>
    <a href="#" class="promote">Promote</a>
    <a href="#" class="remove">Remove</a>
  </p>

  <h2><a href="#"><strong>Google</strong> Maps</a></h2>
  <p>Find local businesses, view maps and get driving directions in <strong>Google</strong> Maps.</p>
  <p class="url">maps.<strong>google</strong>.com
    <a href="#" class="comment">Comment</a>
    <a href="#" class="promote">Promote</a>
    <a href="#" class="remove">Remove</a>
  </p>

  <h2><a href="#"><strong>Google</strong> News</a></h2>
  <p>Aggregated headlines and a search engine of many of the world's news sources.</p>
  <p class="url">news.<strong>google</strong>.com
    <a href="#" class="comment">Comment</a>
    <a href="#" class="promote">Promote</a>
    <a href="#" class="remove">Remove</a>
  </p>
</body>
</html>

I’ve already added Eric Meyer’s CSS Reset file to make your work easy. Preview step 1.

Step 2: Making it prettier

Let’s make it prettier by adding some CSS styles, font colors, paddings and margins. Add the following code below the reset.css file:

<link rel="stylesheet" href="style.css" type="text/css" media="screen" />

Create a file and name it style.css and let’s add some line codes in it:

body{
  padding:10px;
}

strong{
  font-weight:bold;
}

div.header{
  border-bottom:1px solid #c9d7f1;
  padding-bottom:20px;
}

h1{
  float:left;
  margin-right:15px;
}

h2{
  font-size:18px;
  margin-top:20px;
}

h2 span{
  font-size:12px;
}

h2 span.no_comments{
  color:#ccc;
}

p{
  font-size: 14px;
}

p.url{
  color:#008000;
}

p.tags{
  margin-top:20px;
}

It’s not a awesome layout, but it’s good for this example, right? Preview step 2.

Step 3: Adding the CSS Sprites technic

Ok, now that we have a “nice” layout, it’s time to add some CSS Sprites technics. Let’s start with the logo, I’ve made a copy of Google’s sprite image and named it google_sprites.png.

Before we start coding, here’s a trick to find image’s position and size. I’m using Photoshop to create grids and “map” the position of each image, that way I can easily find the X and Y to add in the CSS code. After adding the grids, use the Info window (Windows > Info from menu bar or F8 key) to visualize the values.

Photoshop Grid Sprites

Now we know that the image size for the logo is 137 x 49 pixels and the position is 0 (zero) left and -41 pixels top. Yes, it is -41px top because we want the image goes up, if you insert a positive value, the image will go down. Let’s create the sprites.css and add it just below the styles.css file:

<link rel="stylesheet" href="sprites.css" type="text/css" media="screen" />

Note: while I’m doing the sprites code, some codes will be added to the style.css but will not be here. You can download the ZIP file with all the correct codes at the end of this post. Now, let’s add the code for the logo:

h1{
  display:block;
  overflow:hidden;
  width:137px;
  height:49px;
  text-indent:-5000px;
  background:url('google_sprites.png') no-repeat 0px -41px;
}

I’ve used the image replacement technic, and added the CSS Sprite technic (last line) calling my sprites image and positioning it at 0px left and -41px top. And here is the code for the other elements:

input.btn_search{
  height:30px;
  padding:0 10px;
  border:none;
  color:#fff;
  background:url('google_sprites.png') repeat-x 0px -167px;
}

a.comment, a.promote, a.remove{
  display:inline-block;
  width:16px;
  height:16px;
  overflow:hidden;
  text-indent:-5000px;
  margin-left:2px;
}

a.comment{
  background:url('google_sprites.png') no-repeat -82px -119px;
}
a.comment:hover{
  background:url('google_sprites.png') no-repeat -99px -119px;
}

a.promote{
  background:url('google_sprites.png') no-repeat -137px -55px;
}
a.promote:hover{
  background:url('google_sprites.png') no-repeat -153px -55px;
}

a.remove{
  background:url('google_sprites.png') no-repeat -137px -70px;
}
a.remove:hover{
  background:url('google_sprites.png') no-repeat -153px -70px;
}

And we’re done! Preview step 3.

Conclusion

I may noticed how easy is to work with CSS Sprites, save you time and effort, web storage and bandwidth, and increase your web site’s performance. You can also use YSlow, a Firefox add-on, to review the usage of files and images from your site. If you want, download the files used in this post.

Download css-sprites.zip (29Kb)

Feel free to leave your question or suggestion in the comments below.

December 10, 2009

Setting up your web site to run on iPhone browser

iPhone Safari

According to several researches, the iPhone is the most used mobile to navigate in the Internet. With almost 50% of smartphone web traffic in U.S. and over 30% worldwide, clients are now aware to have their own web page running on iPhone browser. You have be to prepared if requested to create an iPhone web page.

There are many companies offering that kind of mobile services, like MOBIFY and iPhoneMicrosites, but it’s not to difficult to create your own web site running on iPhone browser. It is as easy as making it to run in desktop browsers.

Layout resources and kits

The first thing you will need are resources and kits to create iPhone based layouts. Here are some useful files to assist you:

If you’re looking for some inspiration, CSSiPhone does the job very well.

Home Screen icon

It is a good idea to consider creating an icon to appear as shortcut in iPhone’s home screen. All you have to do is a 57 x 57 pixels PNG image. Safari will crop larger images, so you can create one slightly larger if you want. Then save the file as apple-touch-icon.png and add the following code inside <head></head> node:

<link rel="apple-touch-icon" href="images/apple-touch-icon.png" />

Identifying iPhone browser

Now that you have a layout, there are two possible ways to create an iPhone web page: (1) redirecting the user to a sub-domain running the (a) same content with different layout or (b) a exclusive content for mobile and different layout; (2) switch between CSS files to handle media screen and media handheld (actually, for iPhone is a different type of media). Here is how you’ll handle these two options, insert the codes inside <head></head> node.

PHP:

<?php
  $iphone = strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone');
  $ipod = strpos($_SERVER['HTTP_USER_AGENT'], 'iPod');
  if($iphone || $ipod){
    header('Location: http://m.example.com/');
  }
?>

JavaScript:

if((navigator.userAgent.indexOf('iPhone') != -1) || (navigator.userAgent.indexOf('iPod') != -1)){
  document.location = "http://m.example.com/";
}

Now, if you want to keep the domain, and switch between media types, do the following:

PHP:

<?php
  $iphone = strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone');
  $ipod = strpos($_SERVER['HTTP_USER_AGENT'], 'iPod');
  if($iphone || $ipod){
    print('<link media="only screen and (max-device-width: 480px)" href="iphone.css" type="text/css" rel="stylesheet" />');
  }else{
    print('<link media="screen" href="screen.css" type="text/css" rel="stylesheet" />');
  }
?>

JavaScript:

if((navigator.userAgent.indexOf('iPhone') != -1) || (navigator.userAgent.indexOf('iPod') != -1)){
  document.write('<link media="only screen and (max-device-width: 480px)" href="iphone.css" type="text/css" rel="stylesheet" />');
}else{
  document.write('<link media="screen" href="screen.css" type="text/css" rel="stylesheet" />');
}

In both codes and cases we test the user agent to find iPhone or iPod. That is the way to identify if the browsers is running in an iPhone or in a desktop. But wait, there is more!

Creating a full iPhone page

Let’s use the first case, we’ll redirect the user to a new sub-domain with exclusive content for mobile only. Here is what you have to add:

  • Viewport meta
  • An iPhone icon
  • CSS for iPhone
  • Orientation code

Your HTML should look like this:

<html>
  <head>
    <title>My iPhone page</title>
    <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;">
    <link rel="apple-touch-icon" href="images/apple-touch-icon.png"/>
    <link media="only screen and (max-device-width: 480px)" href="iphone.css" type="text/css" rel="stylesheet" />
    <script type="text/javascript" src="orientation_change.js"></script>
  </head>
  <body>
  </body>
</html>

If you have any need to use the event onorientationchange from iPhone – an event called when you turn your iPhone to the left or the right – use the orientation_change.js file:

window.onorientationchange = function(){
  /*window.orientation returns a value that indicates whether iPhone is in portrait mode, landscape mode with the screen turned to the left, or landscape mode with the screen turned to the right. */

  var orientation = window.orientation;

  switch(orientation){
    case 0:
      /* If in portrait mode, sets the body’s class attribute to portrait. Consequently, all style definitions matching the body[class="portrait"] declaration in the iPhoneOrientation.css file will be selected and used to style "Handling iPhone or iPod touch Orientation Events". */
      document.body.setAttribute("class","portrait");
      /* Add a descriptive message on "Handling iPhone or iPod touch Orientation Events" */
      document.getElementById("currentOrientation").innerHTML="Now in portrait orientation (Home button on the bottom).";
    break;

    case 90:
      /* If in landscape mode with the screen turned to the left, sets the body’s class attribute to landscapeLeft. In this case, all style definitions matching the body[class="landscapeLeft"] declaration in the iPhoneOrientation.css file will be selected and used to style "Handling iPhone or iPod touch Orientation Events". */
      document.body.setAttribute("class","landscapeLeft");
      document.getElementById("currentOrientation").innerHTML="Now in landscape orientation and turned to the left (Home button to the right).";
    break;

    case -90:
      /* If in landscape mode with the screen turned to the right, sets the body’s class attribute to landscapeRight. Here, all style definitions matching the body[class="landscapeRight"] declaration in the iPhoneOrientation.css file will be selected and used to style "Handling iPhone or iPod touch Orientation Events". */
      document.body.setAttribute("class","landscapeRight");
      document.getElementById("currentOrientation").innerHTML="Now in landscape orientation and turned to the right (Home button to the left).";
    break;
  }
}

Code from Ajaxian.

Testing your web site

Now that we have setup the page, it’s time to test it. There are three ways to do it:

  1. Changing the user agent on Safari
  2. Using the iPhone Simulator app
  3. Using the iPhone itself

Both way are very effective, but I strongly recommend iPhone Simulator app, it’s possible to rotate the iPhone to the left and to the right, making it easier to make test. And of course, you can use the iPhone itself to make more real tests – I recommend to use it on final tests only, because improves your development speed.

Enabling Develop menu on Safari

By default Safari comes with no Develop menu. To enable it following these simple steps:

  1. Open Safari Preferences, Safari > Preferences
  2. Select the Advanced tab
  3. Check the option Show Develop menu in menu bar

The Develop menu will appear between Boomarks and Window menus. To change the user agent, just open the Develop menu and chose one of the four options under User Agent option.

Additional resources

Now that you have a running web site on iPhone, feel free to explore more like CSS styles and plugins like jQTouch to make your site even beautiful!