Faster Page Loads With Image Concatenation

[[innerindex]]

Introduction

When designing web applications, icons and images are used to enhance the user experience, give visual cues, and simply look sexy. For complex web apps, the quantity and resulting latency of icons and images used can greatly impact page load times…and developers, in most cases, generally try to reduce page load time with a sweet web app rather than increase it.

To reduce latency in my apps, I use Image Concatenation! Coupled with a bit of CSS magic, performance improves and life is great.

Image Concatenation…WTF?

The basic idea is this: Change X number of image downloads to 1 image download by making 1 big image that contains the X images.

As an example, lets say we have these icons:

help settings maximize shade grow close

While those are pretty tiny in size, on page load the user must still deal with downloading 6 individual images. Instead, we can simply concatenate those images using whatever image software that suits your fancy. Like so:

icons

Displaying Concatenated Images

Now that we have our sweet concatenated image we can’t simply drop that image into an image tag and call it good…that’ll display all icons at once. So…how do we display it?

To display the concatenated image, you need to place that image as a background on an appropriately sized DOM element using CSS to adjust the background positioning to make the appropriate image display. Now, when I say a DOM element…it could really be anything as you can plop a background image on any element with CSS pretty easily:

.whatever{
  background: url('/path/to/image.png');
}

Even though you can use any element, only a few make sense. I’ve seen spans and divs used to accomplish this task, but styling those elements to work cross-browser is flaky at best and really churns my stomach. The element that his handled pretty universally is the img tag.

Yes…yes…I know, I just said don’t place the concatenated image in an img tag. I still hold to that statement. You place the concatenated image as a background on the img tag. So what goes in the src of the img tag? Our old friend the 1 pixel by 1 pixel transparent gif, of course! This way, the image will still act as an image, can be styled like an image, and be super easy to update via CSS.

An Example

Lets say we have the following concatenated image: sidebar_icons that we want displayed in the sidebar with the appropriate links.

Lets set up the HTML first using transparent.gif (a transparent 1×1 pixel image) as the src of the image tags:

...
<ul id="sidebar">
  <li><a href="index.html" title="Home"><img src="images/transparent.gif" class="icon icon-home" alt="Home"/>Home</a></li>
  <li><a href="search.html" title="Search"><img src="images/transparent.gif" class="icon icon-search" alt="Search"/>Search</a></li>
  <li><a href="bookmarks.html" title="Bookmarks"><img src="images/transparent.gif" class="icon icon-bookmarks" alt="Bookmarks"/>Bookmarks</a></li>
</ul>
...

Note the class names on the images…those will be used in the CSS as such:

#sidebar img.icon{
  background: url('/path/to/concatenated/image.gif') no-repeat;
  height: 16px;
  margin-right: 3px;
  vertical-align: middle;
  width: 16px;
}

#sidebar img.icon-home{
  background-position: 0px 0px;
}


#sidebar img.icon-search{
  background-position: -16px 0px;
}


#sidebar img.icon-bookmarks{
  background-position: -32px 0px;
}

That’s really all there is to it. The icon class allows us to set the same image background and dimensions for all icons in the sidebar. The individual classes allow us to change the image that actually shows through.

More CSS Magic

Since CSS is being used to display the appropriate image, you can do your typical property manipulation as normal (e.g. :hover, set transparencies, etc).

A little trick I picked up at Zimbra‘s presentation (the same presentation I learned the benefit of image concatenation) at The Ajax Experience last October was how to reduce the number of images used by representing inactive icons with CSS transparency rather than using individual images for inactive icons. Like so:

#sidebar img.inactive{
  filter:alpha(opacity=50);
  -moz-opacity: 0.5;
  opacity: 0.5;
}

If you wanted to make the icons partially transparent all the time but on mouse over make them 0% transparent, you can do so like so:

#sidebar img.icon{
  filter:alpha(opacity=50);
  -moz-opacity: 0.5;
  opacity: 0.5;
}

#sidebar img.icon:hover{
  filter:alpha(opacity=100);
  -moz-opacity:1.0;
  opacity:1.0;
}

Basically, whatever CSS magic you can weave can be done.

Additional Benefits

If you are a developer working in a painful development environment, the above methods are extremely valuable. Oh…and by painful I mean: any change to the base document structure requires a restart of the application. I’ve been doing a lot of development in an XSLT/Java environment recently and this method has saved me countless restarts :)

Now, if I decide an icon should change from a “house” to a “moon” (for some strange reason) I can make that change easily in CSS without needing to change the XSLT…thus no restart needed. Beautiful.

Heck…I use this CSS method for a number of non-concatenated images as well just so I can make general image changes with ease.

What Not To Do

When using the above image concatenation methods, it is important to note that concatenating similar images is a good plan. Avoid concatenating images of vastly different sizes because the wasted space on the concatenated image increases the amount of data being downloaded which can counter-act what we are attempting to reduce by concatenation.

Drawbacks

Update: This section was added a couple of hours after posting as per someone’s suggestion.
Using this method can affect the printability of your page as background images assigned with CSS don’t show in print too well :)

Conclusion

Image concatenation can be a beautiful thing when dealing with large numbers of icons/images. But, as with anything, weigh its benefit. Thus far, I’m pretty happy with the results!

Guest Lecture: Application Design with Databases

I had the privilege of being a guest speaker at Plymouth State University’s Database Management class. The focus of the lecture was regarding Web Application Design and how it relates to database integration. Here are the slides that were handed out and for those curious, here’s the topics of discussion:

Topics:

  • My Background
  • My Project Background
  • Application Design Process
    • Analysis
    • Language Selection
    • Database Design
    • Interface Design
    • Development
    • The Sweet Stuff
  • Industry
    • Where it was
    • Where it is
    • Where its going
  • Stuff I’ve Learned
  • Suggestions

The Ajax Experience: Leveraging Ajax for Enterprise Application Development

[[innerindex]]

Despite the fact that AJAX is making significant inroads within the Web 2.0 community, many enterprise applications still remain either traditional web or desktop applications. However, by effectively using AJAX, enterprises can develop compelling, innovative, and useful web based applications that increase employee productivity while retaining the manageability enjoyed by traditional web applications. This session will focus on the challenges of developing enterprise AJAX applications with an emphasis on overcoming the common hurdles and problems encountered along the way.

Presenter: Conrad Damon – Zimbra

Conrad’s discussion began with an re-iteration of what Web 2.0 is and how things have changed since Web 1.0. Old news, but the re-iteration was brief.

Choosing an RIA solution

Next Conrad explained his team’s decision process on choosing Ajax as the solution for creating their Rich Internet Application, Zimbra.

Flash?
The Zimbra team turned this down early on as they didn’t want to be tied to a proprietary solution… A decision I can respect :) I’m not too keen on the use of Flash as a front end for full-blown RIAs in most cases.

Ajax Worries
There were some hesitations regarding the use of Ajax as a solution:

  • Complexity – Lets face it, adding Ajax into the mix causes the applications complexity to increase.
  • Performance – there’s a lot going on with an Ajax app client-side that can cause client performance to degrade. (mixed with the chattiness server-side)
  • Some cross-browser issues.

Ajax: The Chosen One
Overall, Zimbra’s team decided on Ajax as the pros outweighed the cons:

  • Enhanced User Experience
  • Desktop application-like feel.
  • Deployment is trivial. – No installation…the application is accessible via the web.
  • The power of mashups is where its at. Its all about SOA (Service Oriented Architecture).

Ajax Points

Conrad noted a few key points regarding Ajax, however:

  • Ajax is cheaper on the server/network
  • Ajax applications are more memory expensive client-side
  • Ajax applications are not a business model
  • Ajax applications are the means not an end

Ajax Tips

Based on the Zimbra team’s experience, Conrad gave some tips:

  • Use an Ajax Toolkit – They simplify things. What you choose is up to you, but the time saved by toolkit use is well worth it.
  • CSS is your friend – bend it to your will
  • Use JSON, not XML – Zimbra has almost fully converted all passing of XML to JSON
    • JSON is easy
    • JSON is fast. Eval’ing JSON is faster than parsing XML by a magnitude of 10!
  • Use Asynchronous XHR (XMLHttpRequest) calls
  • Combine, Compress, and Cache
  • Automate Testing – Zimbra uses QuickTest Pro from mercury to test the Zimbra client.
  • OO, MVC
  • TLS (Transport Layer Security…SSL) – Make sure you use it!
  • KISS (Keep it simple, stupid) – this applies to both code and the UI!
  • No browser lock-in – don’t program for a specific browser…keep it open to at least the A-Grade browsers
  • Test, test, test

Browser Gotchas & Tips

Next came some helpful browser-specific tips and gotchas:

  • Firefox
    • Missing Cursor – workarounds exist (surrounding the input with a div…yadda yadda)
    • Event capture – effects DnD effects
    • design mode – lets you turn the Browser into an editor…buggy
    • xmlHttpRequest – bug that pained the CPU when making synchronous calls
    • opacity (linux) – hangs browser (relationship between X11 and opacity)!!!!!!!!!!!!!!
    • scrollbar bleed (mac) – scrollbar does not respect z-index
  • IE 6
    • string concat with +… – SLOW, use Array joins instead
    • image caching is poor – hard to convince to cache image in browser…workaround: have a hidden div and load the images there first
    • JS engine can be slow
    • Memory leaks – circular reference issue. workaround: give things numeric ids and a lookup table
    • XHR ActiveX object – some memory leaking issues
    • DOM attribute access is slow
  • IE 7
    • ActiveX opt-in
    • CSS fixes
    • Native XHR
    • memory leaks appear to be fixed
  • Safari
    • No design mode
    • DOM API not fully implemented
    • Debugging difficult (not entirely true)

The 3 C’s

By far the most useful section of Conrad’s presentation was on Zimbra’s 3 C’s; Combine, Compress, and Cache.

Combine
Zimbra uses this technique to minimize the sheer amount of files downloaded by the client which speeds up load time! Conrad suggests:

  • Concatenate your JS files and CSS files – Order matters (remember)! Zimbra uses the “Jammer” ANT task to do this dirty work.
  • Merge Images – Images are expensive! If your application uses a large number of icons, try merging them into a single image and use background-positioning on elements for the display of icons. For disabled icons, use opacity at 20-50% rather than creating a whole new icon.

Compress
Compression makes things smaller in size…smaller “things” are quicker to download!

  • Strip comments and whitespace – use JSMin or ShrinkSafe
  • GZIP your Javascript! – All of the A-Grade browsers support gzipping which reduces file size!

Caching
Set proper headers for appropriate browser caching. Avoid redundant downloads. Period.

Conclusion

I respect the Zimbra team and their decisions; their application is solid, functional, and quite sexy. All in all, this was a pretty solid presentation with a nice amount of data. As I mentioned earlier, the 3C’s were the most valuable tid-bits of information for me…although there were a few browser gotchas that I wasn’t aware of.

Site Redesign

It was high time I re-design BorkWeb. I’ve been screwing around with this design for a few weeks now and I’ve finally got it working for go-live today :D I began construction on the site using LifeAfterCoffee’s Caffeine Theme. Jon did a great job in structuring the templates and a fairly solid CSS stylesheet.

However, I took it and butchered it beyond recognition. I did a lot of restructuring of the templates, location of elements, and I ripped apart the CSS stylesheet and pasted its parts back together with a some additions. I’ll adjust this theme some more, add a header graphic, zip it up and make it available for download soon.

UPDATE: I already think this needs more work….hrm. I’ll have to brainstorm on what to do to it.

Slashdot Redesign

slashdotLast month Slashdot held a very open-ended competition for a redesign of the long overdue layout. I had initially thought I’d enter but laziness took the best of me and I never completed my design. The winner was Alex Bendicken who created a pretty clean and snazzy design. CmdrTaco estimates that the new design will go live in a couple of days…say goodbye to the eyesore that was the circa 1990’s layout.

The winner of the contest will be receiving a sweet laptop (valued at up to $4000) plus the bragging rights of redesigning one of the world’s most popular tech/geek blogs. Good times. Over the course of the contest I had been hoping Peter Lada’s design would win out, but Alex’s is just as snazzy (with fewer frills) so I’m happy.

Writing Your Server-Side Ajax Handler

[[innerindex]]In my recent post on ‘Ajax; Templating; and the Separation of Layout and Logic,’ I refer to an Ajax Handler that sits server side to handle Ajax calls. Some elaboration is in order.

As I have stated in the past, I’m a huge fan of Prototype AND I choose PHP as my language of choice…so my examples will be using both, but the idea is portable.

Set up your Functions

Before you create a handler, you need a set of functions that the handler can reference. Here’s an example:

< ?php
function world($params='')
{
  return 'Goodbye Cruel World.';
}//end world

function sweetWorldAction($params='')
{
  //we expect params to be an array or a string similar to a parameter string from a GET..i.e. "bork=asdf&cheese=yes please"
  //parse out the variables
  if(!is_array($params))
  {
    parse_str($params,$params);
  }//end if

  //do your logic here
}//end sweetWorldAction
?>

Now that we have the functions all set, we’ll set up a handler that receives Ajax calls and calls the appropriate functions.

The Eval Method – A Dynamic Handler

This method is one that I toyed around with for a while and I’ll admit that its pretty simple and clean but there are some drawbacks. We’re going to make a few assumptions: All requests will be GET (this is to keep things simple for this example) and we will keep the complexity of .htaccess sweetness out of these examples and assume that each call will be passing a function variable that specifies the function we are calling. I’ll get to those in a second…but first I’ll show you the handler code in this Eval Method:

< ?php
//if the user leaves the page or closes the browser prematurely, this will help prevent half completed statements
ignore_user_abort();

include('functions.php');

//list out your Ajax accessible functions
$valid_functions = array('world','sweetWorldAction');

if($_GET['function'] && in_array($_GET['function'],$valid_functions))
{
  //get the get parameters
  $params = $_GET;  
  //unset the function index from the params because we just don't need it there
  unset($params['function']);

  //build your parameter string:
  $param_string='';
  foreach($params as $key=>$param)
  {
    $param_string.=(($param_string)?'&':'').$key.'='.$param;
  }//end foreach

  //make your function call
  eval($_GET['function']."('$param_string');");
}//end if

?>

The Variable Variable Method – A Dynamic Handler

This method (compliments of PHPDeveloper) is simpler than the Eval Method and just as dynamic.

< ?php
//if the user leaves the page or closes the browser prematurely, this will help prevent half completed statements
ignore_user_abort();

include('functions.php');

//list out your Ajax accessible functions
$valid_functions = array('world','sweetWorldAction');

if($_GET['function'] && in_array($_GET['function'],$valid_functions))
{
  //get the get parameters
  $params = $_GET;  
  //unset the function index from the params because we just don't need it there
  unset($params['function']);
  //make your function call
  $_GET['function']($params);
}//end if

?>

The Switch Method – A Basic Handler

This method handles each call individually. The reason for using switch rather than if-elses is simply because your application will most likely possess a large number of Ajax-ified functions and those if-elses would be ghastly to read and decrease performance…the Switch statement is much cleaner.

< ?php
//if the user leaves the page or closes the browser prematurely, this will help prevent half completed statements
ignore_user_abort();

include('functions.php');

if($_GET['function'])
{
  switch $_GET['function']
  {
    case 'world':
      echo world();
      exit;
    break;
    case 'sweetWorldAction':
      echo sweetWorldAction();
      exit;
    break;
  }//end switch
}//end if

?>

Make a Choice

Which are you going to use? While the Eval and Variable Variable Methods contain very small amounts of code in the handlers, the logic has simply been shifted to the functions themselves. Increased Ajax-geared logic within the functions themselves reduces portability. However, in the Switch Method, logic is organized in a fairly easy to follow manner while making use of very generic functions that can be used in multiple fashions. Obviously, the Switch Method is my preferred choice :)

In Closing

Handler scripts make the Ajax magic happen and the separation of handler logic from your application logic is just as important for robust development and debugging as the need for separation of layout and logic. Play around with the above methods and see which works for you. If you have a method all your own, I’d be interested to hear it!