Aptimize: realtime spriting and more

October 5, 2009 10:04 pm | 26 Comments

I love evangelizing high performance best practices and engaging with developers who are focused on delivering a fast user experience. Helping to optimize the Web appeals to the (speed)geek in me, and my humanitarian side feels good about creating a better user experience.

There are many companies and developers out there that go the extra mile to deliver a fast web page. My hat’s off to you all. It can be hard to maintain a high performance development process day-in-and-day-out. Heck, it can be hard to even understand all the performance optimizations that are possible, and which ones make sense for you. I savor the challenge this presents, for the same reason that I resonate with what Jimmy Dugan (Tom Hanks) says to Dottie Hinson (Geena Davis) in A League of Their Own when she complains about how hard playing baseball is:

It’s supposed to be hard. If it wasn’t hard, everyone would do it. The hard… is what makes it great.

As much as I love the skills it takes to build fast web sites, I also want a majority of sites on the Web to get a YSlow A. Right now, the bar is just too high. For fast web sites to become pervasive, web development needs to be fast by default. Performance best practices need to be baked into the most popular development frameworks and happen automatically. We’re seeing this with browsers (parallel script loading, faster JavaScript engines, etc.) and in some frameworks (such as SproutCore and WordPress). I predict we’ll see more frameworks and tools that deliver this fast by default promise. And that’s where Aptimize comes in.

I’ve been tracking Aptimize for about a year since they contacted me about their Website Accelerator. I was psyched to have them present at and sponsor Velocity. Website Accelerator changes web pages in real time and injects many of the performance best practices from my books, plus some others that aren’t in my books. It’s a server-side module that runs on Microsoft Sharepoint, ASP.NET, and Linux/Apache. One of their more high profile users wrote up the results last week in this blog post: How we did it: Speeding up SharePoint.Microsoft.com.

Here are some of the before-vs-after stats:

  • # of HTTP requests empty cache went from 96 to 35
  • # of HTTP requests primed cache went from 50 to 9
  • empty cache page load times were reduced 46-64%
  • primed cache page load times were reduced 15-53%

These results were achieved by automatically applying the following changes to the live pages as they left the server:

  • concatenate scripts together (goes from 18 to 11 requests)
  • concatenate stylesheets together (goes from 17 to 5 requests)
  • create CSS sprites and inline images using data: URIs (goes from 38 to 13 requests)
  • add a far future Expires header
  • remove duplicate scripts and stylesheets
  • minify (remove whitespace, etc.) in scripts and stylesheets

You can see the results by visiting sharepoint.microsoft.com. (Compare the optimized page to the before page by adding “?wax=off” to the URL. Get it? “wax=on”, “wax=off”?? The Aptimize team is from New Zealand, so they’re always up for a good laugh. Note that once you use the querystring trick you might have to clear your cookies to move between versions.) You know you’re looking at the optimized page if you see URLs that start with “http://sharepoint.microsoft.com/wax.axd/…”.

With my recent work on SpriteMe, I was most interested in how they did CSS sprites and used data: URIs. Here’s one of the sprites Aptimize Website Accelerator created automatically. They don’t create it on-the-fly for every page. They create the sprite image and cache it, then reuse it on subsequent pages.

I was especially impressed with the work they did using data: URIs. Data: URIs are a technique for avoiding the extra HTTP request for files (typically images) by embedding the encoded response data directly in the HTML document. The main problem with data: URIs is that they’re not supported in IE7 and earlier. Recent blogs from web dev performance rock stars Stoyan Stefanov and Hedger Wang discuss a workaround for early versions of IE using MHTML. Aptimize has already incorporated these techniques into their product.

To see this in action, go to sharepoint.microsoft.com in a browser other than IE. I’m using Firefox with Firebug. Inspect the printer icon next to “print friendly” at the bottom of the page and you’ll notice the background-image style looks like this:

url(data:image/gif;base64,R0lGODlhGAAaALMJA...

That’s the base64-encoded image. It’s declared in the MSCOMSP-print rule inside this Aptimize-generated stylesheet.

Inspect the same “print friendly” icon in IE7 and you’ll see this background-image:

url("mhtml:http://sharepoint.microsoft.com/wax.axd/cache/2fpw31-aG1G4JD2$a$MeCg.mhtx!I_aWWORG5UHNr6iB8dIowgoA")

This is worth understanding: “mhtml” tells IE this is MIME HTML. The URL, http://sharepoint.microsoft.com/wax.axd/cache/2fpw31-aG1G4JD2$a$MeCg.mhtx, points to multipart response. The location, I_aWWORG5UHNr6iB8dIowgoA, identifies which part of the multipart response to use. There we find the same base64-encoding of the printer icon.

Most sites avoid data: URIs because of lack of cross-browser support. The MHTML workaround has been known for awhile, but I don’t know of many web sites that understand this technique, let alone use it. And here we have a tool that adds this technique to your web site automatically. Well done, Aptimize.

26 Comments

dynaTrace Ajax Edition: tracing JS performance

September 30, 2009 11:27 pm | 4 Comments

DynaTrace has been around for several years focusing on the performance analysis of backend applications. They entered the frontend performance arena last week with the release of dynaTrace Ajax Edition. It’s a free tool that runs in IE as a browser helper object (BHO). I tried it out and was pleased. It’s important to have development tools that work in IE. I love Firefox and all its add-ons, but I also know how important it is to test on IE and more importantly to be able to debug on IE.

Once you’ve downloaded and installed DAE (my shorthand name for dynaTrace Ajax Edition), don’t be fooled if you don’t see an easy way to start it from within IE. You have to go under Programs in the Start Menu and find the dynaTrace program group. Entering a URL for the first test run is obvious. For subsequent runs, click on the “play” icon’s menu and pick “New Run Configuration…” and enter a different URL. One of the nice features of DAE is that it can run during a multi-page workflow. You can enter the starting URL, and then navigate to other pages or launch Ajax features while DAE monitors everything in the background. When you close IE you can dig into all the info DAE has gathered.

DAE gathers a ton of information on your web app. My main issue is that there’s so much information you really need to play with it for awhile to discover what it can do. This isn’t a bad thing – slightly challenging at the beginning, but once you know how to navigate through the UI you’ll find the answer for almost any performance or profiling question you have. I kept finding new windows that revealed different views of the information DAE had collected.

The main differentiator of DAE is all the JavaScript profiling it does. Time is broken out in various ways including by event triggers and by JavaScript API (libraries). It has an HTTP waterfall chart. A major feature is the ability to save the DAE analysis, so you can examine it later and share it with colleagues. There are other features that are more subtle, but pleasant to run into. For example, DAE automatically UNminifies JavaScript code, so you can look at a prettified version when debugging a live site.

When it comes to analyzing your JavaScript code to find what’s causing performance issues, dynaTrace Ajax Edition has the information to pinpoint the high-level area all the way down to the actual line of code that needs to be improved. I recommend you give it a test run and add it to your performance tool kit.

4 Comments

Web Exponents speaker series

September 29, 2009 8:29 pm | 4 Comments

Earlier this year I started a speaker series at Google that I call Web Exponents. The word “exponents” is used in the context of “a person who actively supports or favors a cause”. I even have a tagline: raising web technology to a higher power. Classic.

I post about these talks on the Google Code Blog. I recommend you subscribe to that blog, but in case you don’t, I wanted to cross-post here to make sure people catch the great talk by Chris Anderson on CouchDB.

Other speakers in the Web Exponents speaker series include:

Each blog post contains links to the video and slides for each talk. Keep your eye open for upcoming speakers in the next month or two.

4 Comments

Yahoo! Search – new features, faster performance

September 28, 2009 8:24 pm | 4 Comments

My last blog post was about Mobile Gmail performance best practices. It’s nice to follow that up with a review of a recent YDN blog post: Not Just a Pretty Face: Performance and the New Yahoo! Search. It’s great to see these industry leaders sharing their performance tips with the developer community and showing the high value they put on making web pages faster.

Yahoo! Search recently added several rich new features. Along with that came many performance improvements, resulting in a launch that not only had more features but was faster than the old version. What?! More features and faster performance?! Yes, you can have your cake and eat it, too. Here are some of the performance optimizations you can find in the new Yahoo! Search:

data: URIs

Any HTML attribute that accepts a URL can also accept a data: URI – an encoded version of the actual HTTP response. This is a best practice for reducing the number of HTTP requests. Yahoo! Search converted several of their CSS background images into data: URIs. For example, the gold Search button’s background looks like this:

If you look at their stylesheet, you’ll see that the background image uses a data: URI rather than an image URL:

.sbb {background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSU...rkJggg==');}

Using data: URIs instead of separate images eliminates HTTP requests. Even better, because the data: URI is in an external stylesheet (as opposed to the HTML document itself), it can be cached.

page flushing

Flushing the document early is a best practice I evangelize in Even Faster Web Sites. Sending the HTML header and top navbar as quickly as possible allows the browser to start rendering the page more quickly. This visual feedback gives the user an experience that feels faster. If there are any resources in the head, the browser can get a jump on downloading them while the rest of page is still being stitched together. Yahoo! Search! sends down an initial chunk that includes the page header and search box. This HTML is fairly static, so the backend server can generate it quickly, before starting on the actual search results.

Yahoo! Search goes even farther. The next chunk contains the remaining visible page content, but no JavaScript. The JavaScript is downloaded last, progressively enhancing the functionality of the page. This is a pattern I’m seeing more and more, especially in JavaScript-intensive web apps.

lazy loading

Yahoo! Search divided the JavaScript and CSS in the search results page into two categories: the bare minimum required to render the basic page and additional (heavy) functionality such as Search Assist and Search Pad. This is similar to another of my performance best practices: Splitting the Initial Payload. My advice focuses on JavaScript, but Yahoo! Search has extended the optimization to include CSS.

My post on Mobile GMail talked about their approach to lazy-loading JavaScript that avoids locking up the browser. Yahoo! Search uses the Script DOM Element approach – create a script element, set its src, and append it to the head element. This is a great approach for loading scripts in parallel. Yahoo! Search lazy-loads three scripts, so parallel loading is important. This technique does cause the JavaScript to be parsed and executed immediately. This isn’t an issue if it’s a small amount of code or the functionality is needed immediately. Otherwise, downloading the JavaScript and delaying the parsing and execution might lead to an even faster user experience.

Kudos to the Yahoo! Search team. Great work, and thanks for sharing!

4 Comments

Mobile Gmail and async script loading

September 26, 2009 5:17 pm | 11 Comments

Mobile is the current web frontier where we’ll see the greatest growth in users and companies over the next few years. In case you didn’t see the announcement, Dion Almaer and Ben Galbraith just joined Palm to head up their developer relations program. At this week’s Velocity kick-off meeting, mobile performance was highlighted as a primary focus for next year’s conference.

With mobile on my mind, I was blown away by the awesome performance tips in this blog post: Gmail for Mobile HTML5 Series: Reducing Startup Latency. This post hits on the main point of my recent book – the impact of loading JavaScript. This is the #1 performance issue for today’s web apps. The problem is even worse for mobile devices where download times can be significantly worse than on the desktop.

One of the best practices I evangelize is splitting the initial payload. The Google Mobile team echoes this advice, recommending that fast mobile web apps must separate their code into modules that are critical to page startup versus modules that can be lazy-loaded. It’s important to carefully consider when to lazy-load this additional JavaScript.

One strategy is to lazy load the modules in the background once the home page has been loaded. This approach has some drawbacks. First, JavaScript execution in the browser is single threaded. So while you are loading the modules in the background, the rest of your app becomes non-responsive to user actions while the modules load. Second, it’s very difficult to decide when, and in what order, to load the modules. What if a user tries to access a feature/page you have yet to lazy load in the background? A better strategy is to associate the loading of a module with a user’s action.

Loading JavaScript in the background does indeed freeze the UI and lockout the user. Even worse, they don’t know why this is happening. They didn’t invoke any action – the lazy-load was kicked off in the background. But, I’ve seen web apps adopt this recommendation of loading modules when the user requests the additional functionality, and that’s not pretty either. Waiting for a script to download, especially over mobile connections, injects too much of a delay. But the Google Mobile team found an ingenious workaround:

…we wrote each module into a separate script tag and hid the code inside a comment block (/* */). When the resource first loads, none of the code is parsed since it is commented out. To load a module, find the DOM element for the corresponding script tag, strip out the comment block, and eval() the code.

Your parents were wrong – you can have your cake and eat it, too! Commenting out the JavaScript code avoids locking up the browser, so the actual download can happen in the background without affecting the user experience. Once the code arrives, modules are eval’ed on an as-needed basis, without the delay of actually downloading the script. The eval does take time, but this is minimal and is tied to the user’s actions, so it makes sense from the user’s perspective.

I’ve been working on ways to download scripts asynchronously for two years. I’ve never seen this technique before. It’s very promising, and I hope to explore a few enhancements. It sounds like Google Mobile did the download as an HTML document in an iframe (“each module in a separate script tag”). This means it would have to be downloaded from the same domain as the main page – something common at Google but less typical on other web sites using CDNs or Google AJAX Libraries API, or sharding resources across multiple domains. It would be nice if each module could be a standalone script with the code commented out. This would avoid the same domain restrictions, and be faster since the scripts could be downloaded in parallel.

Hats off to the Google Mobile team. And thanks for sharing!

11 Comments

Sau-dərs: “sour”, not “super”

September 22, 2009 8:52 pm | 7 Comments

After my exhausting three part post on SpriteMe, I need a lighter one tonight. Often at conferences I’ll be introduced as Steve Sü-dÉ™rs (like “super”). The spelling is almost always correct, “Souders”, but most people mispronounce my last name, so I don’t say anything. But I wanted to get the official pronunciation out there: it’s Sau-dÉ™rs (like “sour”). Would I rather be “super” than “sour”? Yes. But that’s just the way this cookie crumbles.

I found out last week that Nicholas pronounces his last name Zā-kÉ™s, not Za-kÉ™s. If your name gets mispronounced, or you know someone else who’s name gets butchered, feel free to clear that up right here.

7 Comments

SpriteMe (part 3)

September 21, 2009 11:59 pm | 3 Comments

This is the third of three blog posts about SpriteMe. The first post, SpriteMe makes spriting easy, reviews SpriteMe’s features with a summary of the performance savings across the Alexa U.S. top 100 web sites. The second post, SpriteMe (part 2), talks about my experience at WordCamp that motivated SpriteMe and the logic behind how SpriteMe makes its recommendations for creating sprites. This post discusses issues around sprite file size (and memory size) and wraps up with thoughts on major next steps.

File (and Memory) Size

In SpriteMe makes spriting easy, I showed how running SpriteMe on the Alexa U.S. Top 100 eliminated eight HTTP requests on average, but resulted in a 6K increase in total size of background images. Although this is a beneficial tradeoff (8 fewer requests in exchange for 6K more data), I’d prefer to see a reduction in overall size. After all, combining images into a single sprite reduces the amount of image formatting information, and frequently produces a savings.

The primary reason that SpriteMe produces an overall size increase is because of colors. Images that use 255 colors or less use a smaller color palette and have a smaller file size. Currently, SpriteMe has no knowledge of the number of colors, and which colors, an image uses. It’s possible for SpriteMe to combine two images, each of which is 255 colors or less, into a sprite that exceeds 255 colors, resulting in an overall increase in size. In the future, I plan on having SpriteMe use a web service to provide color palette information (issue #17). Until then, if SpriteMe produces a significant size increase, you can manually rearrange the images to stay within the 255 color threshold. Try grouping similarly colored images together. Fortunately, SpriteMe makes it easy to try different combinations and immediately see the size of the resulting sprite.

Another size concern has to do with memory size. As pointed out by Vladimir Vukićević in his post To Sprite Or Not To Sprite, although an image file can have a high degree of compression, most browsers render an image based on dimensions, allocating the same amount of memory for each pixel. The image he cites as an example is a 1299×15000 png. The download size is only 26K, but because of the huge dimensions the image consumes 75M when loaded in Internet Explorer, Firefox, Safari, and Chrome. (Not Opera, however – hmmmm.) Luckily, I’ve never seen SpriteMe recommend a sprite even close to this size. Even so, SpriteMe currently doesn’t “pack” images when it lays them out in the sprite, but that is on SpriteMe’s future feature list (issue #53). If SpriteMe generates a sprite with extremely large dimensions, try grouping narrow images in one sprite, and wide images in a different sprite.

Big Ticket Items

SpriteMe has about 50 open issues currently, but these are the major features I look forward to seeing added to SpriteMe:

export modified CSS
The #1 requested feature is an easier way to export the CSS changes (background-image and background-position). Ideally, SpriteMe would display the exact rule with the appropriate modifications. But, as with many things, the devil is in the details. The CSS changes might occur across multiple rules. Tracking down the exact rules is challenging, given how styles cascade. Finally, the rule’s cssText available through the DOM is unlikely to match the original CSS, and yet developers want something as close to their original code as possible, to make it easier to diff. And, of course, the way to do this differs across browsers. This isn’t impossible, but it’s going to be very hard.
create foreground IMG sprites
SpriteMe eliminates eight HTTP requests on average across the Alexa U.S. top 100 web sites. For some sites, over thirty requests are eliminated. But an even greater potential for savings can be had by spriting normal “content images”. These are the images embedded in the page using the IMG tag. This is possible, and I’ve seen web sites that do it, but it adds a fair amount of extra complexity. The IMG tag must be wrapped by a DIV with style “position: relative; display: inline-block; overflow: hidden; width: <img-width>; height: <img-height>;”. Then the IMG’s style is set to “position: absolute; left: <sprite-offset-x>; top: <sprite-offset-y>;”. I need to test this more, gauge the potential benefits are, and see if it can be done in an intuitive way.
sprite image editor
Creating and testing sprites is a challenge, but maintaining sprites is also difficult. One idea is to retain a memory of the images that were combined into the sprite for more intelligent editing later on. For example, for each background image added to a sprite, it’s original URL and coordinates (upper-left and lower-right) can be recorded. This information would be saved in a separate manifest file or added to the sprite itself as comments. Later, a special sprite image editor could make it easy to refresh or replace one of the background images, without affecting any of the other images in the sprite.

SpriteMe’s ability to modify the live page is a powerful feature. This speeds up the development process by promoting faster iterations. I’d like to find more opportunities for this style of development. One example, somewhat related, could be with image optimization. Page Speed compresses the page’s images on-the-fly using lossless techniques. A button that swapped out the bloated images for the optimized images would allow developers to verify the quality of the images before updating their files.

Spriting is a difficult task. SpriteMe makes the job easier. We’re seeing more and more tools that help developers build high performance web sites. Add SpriteMe to your developer toolkit, and stay tuned for a rash of posts about other performance tools that have recently entered the scene.

3 Comments

SpriteMe (part 2)

September 18, 2009 11:23 pm | 6 Comments

This is the second of three blog posts about SpriteMe. The first post, SpriteMe makes spriting easy, reviews SpriteMe’s features with a summary of the performance savings across the Alexa U.S. top 100 web sites. This post talks about my experience at WordCamp that motivated SpriteMe and the logic behind how SpriteMe makes its recommendations for creating sprites. The third post, SpriteMe (part 3), discusses issues around sprite file size (and memory size) and wraps up with thoughts on major next steps.

The Motivation

I had a cool idea for my talk at WordCamp this past May: I would optimize a WordPress theme live onstage. The night before (says the procrastinator), I sat down to do a dry run. It only took me about 30 minutes to do most of the performance optimizations (Apache cache and compression settings, move scripts to the bottom, commandline YUI Compressor, etc.).

The final optimization was creating CSS sprites from the various background images in the theme. Here’s the process I went through:

  1. Run YSlow to find the CSS background images.
  2. Download the images and zip them.
  3. Create the sprited image using CSS Sprite Generator.
  4. Download the sprited image to my server.
  5. Edit the CSS that used one of the old background images to use the new sprite image and add a background-position using the offsets provided by Sprite Generator.
  6. Reload the page.
  7. Visually determine which backgrounds were broken.
  8. Repeat parts of steps 2-7 multiple times trying to find the right combination of images and background-position values.

Hours later, I had figured out a fairly good number of images to sprite together and the necessary CSS changes to retain the page’s original rendering. But it had taken waaaaay too long. That’s when I decided to create SpriteMe.

Spriting Logic

The hardest part of building SpriteMe was figuring out which background images could be sprited, and how they could be combined. Most of what I now know about sprites I learned in the last few months, so it’s important for me to document this logic and encourage CSS gurus to give feedback. Here’s the high-level logic that spriteme.js currently uses behind its sprite suggestions:

skip images that repeat-x AND repeat-y
Images that repeat both vertically and horizontally can’t be sprited because neighboring images would be visible.
skip images that are very “short” and “narrow”
A “short” background image has a height that is smaller than the height of its containing block. Similarly, the width of a “narrow” image is smaller than the width of its containing block. An image that is short and narrow can be sprited as long as there’s enough padding (whitespace) around it to make up the difference between it and its containing block. If this padding is too large, adding a short and narrow image to a sprite might result in an increase in the size of the sprite image (both file size and memory footprint) that negates the benefits of spriting. Background images that are only short or only narrow can be sprited and are addressed below.
sprite repeat-x images of similar width together vertically
The key with horizontally repeating images is that there can’t be any padding to the left and right of the image – anything on the sides will bleed through with each repeat. Thus, repeat-x images can be sprited in a vertically-stacked sprite if the sprite is the same width as the image. SpriteMe started by only spriting repeat-x images with the same width. I expanded that to enable spriting images of different widths, as long as a least-common-multiple of their widths could be found that was 20px or less. For example, repeat-x images with widths of 2, 3, and 9 could be sprited in an image 18px wide. This is done by replicating the 2px image nine times, the 3px image six times, and the 9px image twice. (Repeat-x images greater than 20px can still be sprited together, but only with other repeat-x images of the exact same width.)
sprite repeat-y images of similar height together horizontally
Repeat-y images of similar height are sprited together just as repeat-x images of similar width are sprited together. (See the previous bullet.)
sprite “short” images together horizontally
Imagine a background image (such as a watermark) that is dramatically shorter than the containing block – maybe the background image is 10px high and the containing block is 500px high. This image can’t be sprited vertically – it would require 490px of padding above or below it. But it can be sprited vertically. (These images are not narrow and do not repeat – those cases fit into one of the prior bullets.)
sprite everything else vertically
Background images that don’t fall into any of the above categories can be sprited vertically. These are images that don’t repeat AND are not short. In summary, they are about the same size as (or smaller than) their containing block, or they’re narrow

The logic above catches most of the opportunities for spriting, but I’ve thought of a few more situations where it might be possible to eliminate one or more additional image requests:

  • Currently, SpriteMe puts repeat-x images in one sprite, and non-repeating images in a different (vertically-stacked) sprite, and never the twain shall meet. But repeat-x images could be added to the non-repeating sprite so long as they were the same width. (The repeat-x images could be replicated to achieve an equal width as described previously.) This would result in one fewer sprite image. The same could be done with repeat-y images and a non-repeating horizontally-stacked sprite.
  • Images that are exceedingly “short” aren’t sprited. But if one such image is positioned at the bottom of its containing block, it could be placed at the top of a vertically-stacked sprite. Similarly, if it’s positioned at the top of its containing block, it could be placed at the bottom of a vertically-stacked sprite. This logic could be applied to “narrow” images, too, placing them to the left or right of a horizontally-stacked sprite. In the best case, this could eliminate an extra four HTTP requests.
  • I’ve seen some images styled to repeat, but their containing block is the same size or smaller than the background image. These could potentially be sprited as if they weren’t repeating.

Finally, SpriteMe doesn’t sprite these images:

  • jpegs – It’s totally feasible to sprite jpeg images, but while testing SpriteMe on popular web sites I found that the resulting sprite was much larger than the total size of the original background images (50K or more). A common cause was combining jpegs with images having 255-or-fewer colors. Until SpriteMe gets knowledge about color palette (issue #17), it skips over jpeg images.
  • firewalled images – SpriteMe uses the coolRunnings service to create the sprite. This is done by sending the background image URLs to the coolRunnings service. If the URL is behind a firewall or otherwise restricted, it can’t be sprited.
  • 0x0 elements – When generating sprite suggestions, SpriteMe examines the height and width of DOM elements with a background image. In some cases (drop down menus, popup DIVs), these DOM elements haven’t been rendered and have a zero height and width. If all of its DOM elements have a zero height and width, that background image is not sprited.

This is a thorough (i.e., lengthy) deep dive into the rules of spriting. I plan on expanding this write-up with figures as part of the SpriteMe documentation. My hope is that the logic behind SpriteMe will eventually be used in tools that make web sites fast by default, like Aptimize and Strangeloop Networks. But using this logic in production environments is still a ways off. That’s why it’s important to capture this logic in this post and in SpriteMe, and to solicit your feedback.

In my next blog post about SpriteMe, I’ll talk about ideas for reducing the sprite file size, and big items on the todo list.

6 Comments

SpriteMe makes spriting easy

September 14, 2009 8:41 pm | 21 Comments

I’m excited to announce SpriteMe – a tool that makes it easy to create CSS sprites. It’s a bookmarklet, so it runs in Internet Explorer, Firefox, Safari, and Chrome. Just drag&drop this link to your bookmarks toolbar or right-click to add it to your favorites: SpriteMe.

A CSS sprite combines multiple background images into a single image. Spriting makes web pages faster because it reduces the number of HTTP requests required to load a web page. The problem is, creating sprites is hard, involving arcane knowledge and lots of trial and error. SpriteMe removes the hassles with the click of a button. Try the tutorial to see SpriteMe in action.

Features

Other sprite tools (like CSS Sprite Generator and CSS Sprites generator) are useful for combining multiple background images into a single sprite image. This is a big help, and I’ve frequently used these tools built by Stuart and Ed, and Stoyan. However, the bigger challenges when creating sprites are finding the background images and knowing how to group them into sprites. Once the sprite image is created, testing the sprite, including changing all the CSS, is time consuming. SpriteMe addresses all of these challenges. Here’s a rundown of SpriteMe’s features.

Finds Background Images: SpriteMe makes it easy to examine the CSS background images used in the current page by listing all the background images and the elements that use them. Hovering over its URL displays the background image. Clicking on one of the image’s DOM elements highlights that element in the page.

Figure 1. SpriteMe finds images and the elements that use them, and groups images into sprites.

Groups Images into Sprites: The logic behind spriting is complex: Background images that repeat horizontally can’t be sprited with images that repeat vertically. Repeating images that are sprited together must be the same width or height, depending on whether they repeat-x or repeat-y, respectively. Background images that are shorter than their containing block should go at the top of a vertically-stacked sprite if their position is “bottom”, but they should go at the bottom if their position is “top”. It’s complex – and this is just the beginning of the logic that’s required to avoid mistakes. SpriteMe contains this spriting logic and uses it to suggest which images to combine into a sprite. Figure 1 shows the varied width background images that SpriteMe recommends combining into a vertically-stacked sprite for eBay.

Generates the Sprite: Clicking “make sprite” combines the images into a sprite using the coolRunnings service from Jared Hirsch. No zipping, no uploading form – it just happens. Figure 2 shows the newly created sprite: spriteme1.png.

Figure 2. SpriteMe makes the sprite, recomputes background-positions, and injects the sprite into the page.

Recomputes CSS background-position: Now comes the math. In Figure 1, the background-position for the #Buy element was “0% 100%”. Most sprite generation tools provide background-positions assuming every element starts off being “0% 0%”. Looking at the Alexa U.S. top 10, only 12% (56/459) of the elements that use a background image have a “0% 0%” background-position. More automated help is needed.

SpriteMe, because it runs in the web page, is able to convert the old background-position (“0% 100%”) to the exact offsets needed to use the sprite: “-10px -27px”. Converting “0%” is easy – the sprite has 10px of padding on the left, so must be offset by -10px. The “100%” conversion is harder. The original background image was 45px high. “100%” means the bottom of the image was aligned with the bottom of the DOM element. The DOM element is 28px high (as indicated by “40×28” shown in Figure 2), so we want the 17th pixel of the image to align with the top of the DOM element. This requires an offset of -17px, plus the 10px of padding results in an offset of -27px. Easy, right? Thank goodness for SpriteMe.

Injects the Sprite into the Current Page: As developers, we know it’s critical to optimize the edit-save-test cycle in whatever we’re doing. In the past, the edit-save-test cycle for spriting was painfully long: regenerating the sprite image, saving it back to the server’s “/images/” directory, editing and saving the CSS, clearing the cache, and reloading the page. SpriteMe bypasses all of that by modifying the live page as you watch. In Figure 2, the #Buy element’s CSS has been modified by SpriteMe to use the new sprite, spriteme1.png, along with the new background-position, “-10px -27px”. It might be hard to get excited – success means the page’s appearance doesn’t change at all! But injecting the sprite into the live page means developers can create sprites and verify they work in minutes instead of hours.

The Savings

In all the excitement about features, I almost forgot about the most important part: how much does SpriteMe help reduce HTTP requests? The savings for the Alexa U.S. Top 100 shows SpriteMe replaces 9 background images with 1 sprite on average, for an overall reduction of 8 HTTP requests per page. These stats are tracked using SpriteMe’s “share your results” feature – after running SpriteMe, you can choose to send the savings to SpriteMe’s Savings page. This savings of 8 HTTP requests results in an average increase of 6K in image size. This is a worthwhile trade-off, but ideas for decreasing the sprite file size are in the works.

Savings for the Alexa U.S. top 100

SpriteMe is an open source project, with all the usual links: Code, Group, Bugs, and Contact. In the second blog post, SpriteMe (part 2), I talk about my experience at WordCamp that motivated SpriteMe and the logic behind how SpriteMe makes its recommendations for creating sprites. The third post, SpriteMe (part 3), discusses issues around sprite file size (and memory size) and wraps up with thoughts on major next steps.

21 Comments

Browserscope: how does your browser compare?

September 13, 2009 7:06 pm | 1 Comment

A year ago this week, I launched UA Profiler – a framework for measuring browser performance. Today, Browserscope takes browser profiling to the next level. Browserscope is a full blown open source project, headed up by Lindsey Simon (see his blog post). The framework has been expanded to contain multiple test categories:

These initial tests highlight the strength of Browserscope as a framework to host multiple categories, whether they be new or existing tests. Other test categories being planned include CSS reflow, cookies, and security.

Test results are crowdsourced – anyone can point their browser at Browserscope and run one or all of the tests. Crowdsourcing produces greater browser coverage tested under real world conditions, and lowers Browserscope’s resource requirements meaning the project can run in perpetuity.

We need you to contribute. If you have tests you’d like to see added to Browserscope, review the code, submit a bug, or contact the group. And take a few minutes right now to find out how your browser ranks, and share your results to help build up this repository of browser behavior.

How Does Your Browser Compare?

1 Comment