Implement Small and Background Images Without a Single HTTP Request

We all know the benefits reducing the number HTTP requests has on page performance. With the Mobile Web becoming more and more ubiquitous and its usage predicted to dominate by 2013, performance is even more critical for any semblance of a good user experience. 

The good news is that there are two specific, and often overlooked, techniques that help eliminate unnecessary HTTP requests:

  1. Using data URI to replace small images
  2. Using CSS gradient to replace gradient background images

Let's start with the first technique.

Data URI to replace small images

According to Wikipedia, the data URI scheme "provides a way to include data in-line in web pages as if they were external resources." For performance-conscious developers, that is grounds for celebration! Give me any file, I'll get its base64 string representation and embed it in my page. The content of the file renders fine and I spare an HTTP request to boot!

Heaven!

But like we know from everyday living, there's no such thing as free lunch. Data URIs have their disadvantages. The most annoying one is "blocking." The larger the in-line data string is, the longer the page will remain blocked. 

But there are ways to reduce the blocking time. Optimizing the images beforehand helps reduce the length of the URI string and in turn the duration of blocking. Tools like Smush.it could help in reducing the amount of data packed into an image, which will result into a shorter data URI when converted. Using gzip compression also helps in reducing the overall file size (HTML of CSS files) served to the browser.

Another thing to remember about data URIs is that they don't work in IE 6 and IE 7. One way to resolve this issue is to serve one CSS for IE 6/7 and another for every other browser. This way you can at least boost performance for all compliant browsers while degrading the experience gracefully for non-compliant ones.

I personally like to use data URIs for images that fall in the following categories:

  • patterned background images
  • small images (icons, 1×1, …etc)

Let's take the following image, for example:

Ajax-loader

It's a loading image that's usually used to give visual cue to the user that the page is busy doing something. An image like that cannot be combined in a Sprite, which means that it has to be called in individually through a separate HTTP request. Fortunately, the image falls into the second category of images that qualify for conversion.

Embedding the image in an <img> tag:


<img width="16" height="16" alt="" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />

Embedding the image in a CSS background image:

{
width: 16px;
height: 16px;
background-repeat: no-repeat;
background-image: url(data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==);
}

The raw data for the image is:

data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==

CSS gradients to replace gradient background images

Switching from using Sprites for your gradient background images to using CSS is one of the best practices used to increase web page performance.

Check out the button below:

Vote


 

 

Normally, that button would have had its background served from an image file. Check out how it's done in CSS:

{
background:#fc8433;
border:#ae4805;
color:#fff;
font-size:16px;
padding:5px 10px;
background: -webkit-gradient(linear, left top, left bottom, from(#fc8433), to(#ae4805));
background: -moz-linear-gradient(top, #fc8433, #ae4805);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fc8433', endColorstr='#ae4805');
}

To add the rounded corners, add the following to your CSS class selector:

{
-moz-border-radius: 5px;
border-radius: 5px;
}

These simple examples demonstrate the power of both data URIs and CSS gradients in helping you reduce the HTTP requests. Ultimately, you have to make a decision of what makes sense for your application and performance requirements. But if performance is a concern of yours (as it should be) then you are hard-pressed to peruse your codebase for opportunities to eliminate HTTP requests, and images are a great place to start.

Professional JavaScript for Web Developers by Nicholas C. Zakas

Professional JavaScript for Web Developers by Nicholas C. Zakas

Write Performant and Efficient Javascript
My review on Amazon

I bought this book the day after I attended a session given by Nicholas Zakas (author) at the Velocity Conference in San Jose this year. He offered some brilliant pointers and techniques on writing Javascript code that performs well and is efficient and stable on all browsers.

The book covers all aspects of Javascript in detail and approaches all subjects with an object-oriented mindset. From language basics (data types, variables, objects, functions) and event handling to the Document Object Model (DOM) and the Browser Object Model (BOM) to error handling and debugging to advanced features (custom events, drag and drop) and offline storage just to name a few. He also talks about AJAX, JSON vs. XML and HTML 5 and the new APIs it's bringing. There is also a brief history of language that is written in a much more informative way that in any other book I've read on the subject.

The book puts a lot of emphasis on performance and efficiency, especially when it comes to scope, memory management and algorithm complexity. You will finally learn and understand what closures are all about. You will know how some statements work in some browsers (IE is always the slowest browser.) You will learn a ton of stuff you won't find anywhere else neither online nor in a book.

There is also a section on best practices including maintainability, performance and deployment that I found especially useful.

If you are not a programmer AND just starting to learn Javascript, get Learning JavaScript, 2nd Edition. Otherwise, this is your book. It is essential in any respectable front-end developer's library.

Building iPhone Apps with HTML, CSS, and JavaScript by Jonathan Stark

Building Iphone Apps with HTML, CSS, and JavaScript

Could have been so much better!
My review on Amazon

First off, the title is completely misleading. Almost every chapter in the book covers how to build iPhone-specific web applications using HTML 5 and CSS3 specs. The last two chapters, and only the last two chapters, address converting these iPhone web apps into iPhone native apps using PhoneGap and then submitting them to the Apple Store. Even then, the information covered  in these two chapters was rudimentary at best.

I probably shouldn't have had such high expectations, but the reputation of both the publisher and the author has always been stellar in my book. A title like, "Introduction to Building iPhone Web Apps and Converting Then to Native Apps using PhoneGap" would have properly prepared me for the content of the book. The content in and of itself is excellent–as an introduction, but nothing more.

So if you're interested in building iPhone web apps, this book is a great starting point. If you're interested in building iPhone native apps with web technologies, this book might be a letdown considering the level of your expertise developing iPhone web apps.

document.write and dynamic script injection in Internet Explorer

I have recently run into an issue in all versions of IE (i.e. IE6, IE7 and IE8) when I used document.write to insert a Javascript file onto the page. This is what I was trying to accomplish:

<script type="text/javascript">
document.write('<div id="ad1" style="display:none;">');
document.write('<script type="text/javascript" src="http://someadagency.com/somead?params"><\/script>');
document.write('</div>');
</script>

The problems was that in IE, this is what I get:

<div id="ad1" style="display:none;"></div>[ad content]

Where in Firefox and Safari, I get:

<div id="ad1" style="display:none;">[ad content]</div>

Which is the expected behavior I want. After plenty of online research, I found out that IE defers the processing of any script tag inserted in the document using document.write until it's done processing the parent script tag. To circumvent this problem, I externalized the markup I wanted to wrap the ad in and now my cross-browser solution is:

<script type="text/javascript">
document.write('<script type="text/javascript" src="http://mydomain.com/js/pre_ad_wrapper.js"><\/script>');
document.write('<script type="text/javascript" src="http://someadagency.com/somead?params"><\/script>');
document.write('<script type="text/javascript" src="http://mydomain.com/js/post_ad_wrapper.js"><\/script>');
</script>

Where the content of the two files is basically the one-line document.write statement spitting out the wrapping markup.

I'm using this technique to load in 3rd-party ads at the bottom of the page and relocating them to their propers spots on window load. This has proved to be a major performance boost, especially combined with the other techniques we're using to renders the page.