Optimize Images Using the ASP.NET Sprite and Image Optimization FrameworkBy Scott Mitchell
The HTML markup of a web page includes the page's textual content, semantic and styling information, and, typically, several references to external resources. External resources are content that is part of web page, but are separate from the web page's markup - things like images, style sheets, script files, Flash videos, and so on. When a browser requests a web page it starts by downloading its HTML. Next, it scans the downloaded HTML for external resources and starts downloading those.
A page with many external resources usually takes longer to completely load than a page with fewer external resources because there is an overhead associated with downloading each external resource. For starters, each external resource requires the browser to make an HTTP request to retrieve the resource. What's more, browsers have a limit as to how many HTTP requests they will make in parallel. For these reasons, a common technique for improving a page's load time is to consolidate external resources in a way to reduce the number of HTTP requests that must be made by the browser to load the page in its entirety.
This article examines the free and open-source ASP.NET Sprite and Image Optimization Framework, which is a project developed by Microsoft for improving a web page's load time by consolidating images into a sprite or by using inline, base-64 encoded images. In a nutshell, this framework makes it easy to implement practices that will improve the load time for a web page that displays several images. Read on to learn more!
The Goal: Minimize HTTP Requests
In order to load a web page, the browser must make an HTTP request for the web page's HTML content as well as for any external resources. In their article, Best Practices for Speeding Up Your Web Site, Yahoo!'s Exceptional Performance Team notes: "80% of the end-user response time is spent on the front-end. Most of this time is tied up in downloading all the components in the page: images, stylesheets, scripts, Flash, etc. Reducing the number of components in turn reduces the number of HTTP requests required to render the page. This is the key to faster pages." There are a variety of ways to reduce the total number of HTTP requests needed for a web page. For example, if the page references multiple style sheet files consider combining the multiple files into one. If there are many images on the page consider using sprites or inline images.
Using Sprites to Minimize HTTP Requests
A sprite is a conglomeration of smaller images into one larger image. Imagine a web page that displays nine images like in the screen shot below:
These nine images could be represented as nine separate image files -
date.png, and so on - that would
then each be referenced in the web page via an
<img> element. This approach certainly works, but requires nine HTTP requests for the nine images.
Alternatively, these images could be combined into a sprite, which is a single image that contains all of the smaller images. For example, the image below
is a sprite that comprises the nine images shown in the screen shot above. Note that the sprite is a single image file -
Sprite2.png, in this case - that
contains all nine smaller images of interest.
At this point you may be wondering what good a sprite does us. After all, we want to show just one image at a time - the Bell image next to the words "Ding ding ding!",
for instance - and not all nine images at once. Well, with a bit of CSS we can instruct the browser to display only a portion of the sprite in the browser, namely the
portion that corresponds to the image we want to display. To display the Bell image, for example, we'd use an
<img> element with the following markup:
src attribute is assigned to
blank.png, which we can presume (for the time being) is some 1x1
transparent image file. The real magic happens in the
style attribute, which is where we define CSS rules to have the
element render a 16x16 pixel image using the
Sprite2.png sprite as the background image. The
background-position attribute tells the browser
how to shift the sprite so that the appropriate image is displayed. Because the Bell image is the left-most image in the sprite we do not need to adjust the sprite's position.
To display the Bomb image, however, we'd set the
background-position attribute to
-16px -0px, which would shift the sprite 16 pixels
to the left so that the Bomb image would appear (rather than the Bell image) within the
<img> element's 16x16 pixel window.
There are two primary challenges in using sprites:
- While combining the various images into a single sprite isn't rocket science, it can be a challenging and time-consuming task for a developer who lacks the image editing tools or experience to create a sprite, and
- Correctly displaying a particular image in the sprite requires knowing the image's dimensions and offset within the sprite, as well as knowing the appropriate CSS rules to display just that portion of the sprite.
Using Inline Images to Minimize HTTP Requests
While sprites can greatly reduce the number of HTTP requests - from nine down to one, in our previous example - they still require that the sprite be downloaded. Another option is to use inline images. Typically an
srcattribute references a URL, like
Images/MyDog.jpg. An inline image, however, is one whose actual binary content is specified directly in the
srcattribute as a base-64 encoded string. For instance, the following
srcattribute contains the Bell image's content. Consequently, to render this image the browser doesn't need to make another HTTP request, as the image's content is sitting right there in the
Inline images reduce the number of HTTP requests for images down to zero, but inflate the size of the page. Ideally, an image's inline content would be spelled out in a separate CSS file, where it could then be cached.
The two primary challenges in using inline images are:
- Determining the base-64 encoded string that represents the binary content of the image you want to display, and
- Browser support. Not all browsers support inline images. While Internet Explorer 9 will support inline images, versions 8 and earlier do not. For Firefox, inline image support was added with version 3.5. Therefore, whether you can render an image as inline depends on the browser your visitor is using.
The Solution: Use the ASP.NET Sprite and Image Optimization Framework
The ASP.NET Sprite and Image Optimization Framework is a free and open-source library created by Microsoft. It was designed to simplify using the image optimization techniques we just discussed (using sprites and inline images). In a nutshell, when using the ASP.NET Sprite and Image Optimization Framework you will create a folder in your project named
App_Spritesthat houses those image files you want to combine into a sprite (or display as inline images). The ASP.NET Sprite and Image Optimization Framework will automatically:
- Combine those images into one (or more) sprites, and
- Create two CSS files - one for displaying images from the auto-generated sprite(s) and another for displaying inline images.
ImageSprite.Imagehelper method for MVC applications that generate the necessary markup to display a particular image using either standard
<img>elements, inline images, or sprites, depending on the browser visiting the page.
To get started with the ASP.NET Sprite and Image Optimization Framework you need to visit the download page and get the latest prebuilt DLLs. There are three prebuilt DLLs:
ImageOptimizationFramework.dll- includes the guts of the framework. This assembly must be referenced in order to use any of the framework's features.
WebForms\ImageSprite.dll- includes the ImageSprite Web control, which you can use in an ASP.NET WebForms application for displaying a particular optimized image.
MVC\ImageSprite.dll- includes a helper method,
ImageSprite.Image- used to generate the markup for displaying an optimized image within an ASP.NET MVC view.
Binfolder. (Note that when I created this demo and wrote this article I used the most recent version, ASP.NET Sprite and Image Optimization Framework Preview 2.)
After downloading the ASP.NET Sprite and Image Optimization Framework and adding it to your website, you'll need to register an HTTP Module in
by adding the following markup:
This HTTP Module,
Microsoft.Samples.Web.ImageOptimizationModule, monitors the
App_Sprites folder. If there is any change to this folder - such as
if the images in this folder are modified or deleted or new images are added - this module detects the change and rebuilds the sprite(s) and CSS files used by the
ASP.NET Sprite and Image Optimization Framework.
Next, add an
App_Sprites folder to your website and drop in whatever image files you want to be composed into a sprite. (You can also
create subfolders in the
App_Sprites folder; each subfolder will have its own sprite(s) created.) By default, the ASP.NET Sprite and Image Optimization Framework
will not create a single sprite larger than 450 KB. So if you add more than (roughly) 450 KB worth of images to the
App_Sprites folder, the
ASP.NET Sprite and Image Optimization Framework will break them up into multiple sprites, each smaller than the 450 KB. (This maximum sprite file size, along with other
settings, can be customized by adding a
settings.xml file to the
App_Sprites folder. Refer to the
Word document that is included in the download for more details on this settings file.)
To display an image in the
App_Sprites folder on an ASP.NET page, use the ImageSprite Web control.
An End-To-End Example: Exploring the Demo Application
The demo application available for download at the end of this article has the ASP.NET Sprite and Image Optimization Framework's
WebForms\ImageSprite.dllassemblies in its
Web.configfile has been modified to register the
Microsoft.Samples.Web.ImageOptimizationModuleHTTP Module, and I have created an
App_Spritesfolder and added nine images -
date.png, and so on. There are two ASP.NET pages in this demo of interest:
NonOptimized.aspx- provides an example of a typical web page that displays the nine images in the
App_Spritesfolder using an
<img>element for each image, and
Optimized.aspx- displays the nine images using the ImageSprite Web control. Here, the ImageSprite Web control renders
<img>elements that uses CSS rules and the automatically-created sprite to reduce the number of HTTP requests.
NonOptimized.aspx. This page is painfully simply - it has a three-column, three-row
<table>that displays an image and short bit of text in each cell. The images are displayed using an Image Web control. Here is a snippet of the
Each Image Web control renders an
<img> element whose
src attribute references the specified image. As a result, when visiting this page
the browser must make a total of ten HTTP requests - one for the web page itself and then nine for the nine images. (Actually, the browser makes 12 HTTP requests as there
are two style sheets referenced on this page as well.) You can see these HTTP requests by using an HTTP debugging proxy like Fiddler.
Below is a screen shot from Fiddler showing the time line for downloading these images.
We can reduce the number of HTTP requests by using the ImageSprite Web control. The
Optimized.aspx page contains virtually the same markup as the
NonOptimized.aspx page, the only difference being that in place of the Image Web control the
Optimized.aspx page uses the ImageSprite control.
(Note that to use the ImageSprite Web control on an ASP.NET page you must first register the control, either through
Web.config or via a
on the ASP.NET page.) Here's a snippet of the markup in
Optimized.aspx; note the use of the
<cc1:ImageSprite> control where we previously
The markup rendered by the ImageSprite Web control depends on the browser visiting the page. If the visitor is using Internet Explorer 7 or earlier, the ImageSprite
Web control renders a standard
<img> element, just as if an
<asp:Image> Web control had been used.
If the visitor is using Internet Explorer 8 or a version of Firefox before version 3.5, then the ImageSprite Web control does two things:
- It dynamically adds a reference to the
lowCompat.cssstyle sheet to the page. The
lowCompat.cssstyle sheet is an automatically-generated style sheet that exists in the
App_Spritesfolder and contains CSS rules to display each of the images in the sprite(s).
- It renders an
classattribute is assigned the appropriate class for displaying the specified image.
This ASP.NET page's rendered markup includes a
<link> element in the
<head> section that references the
lowCompat.css style sheet
<img> element. Here's a snippet of the page's rendered markup:
Note that the
class attribute is assigned to the class name
bomb-png. This class is defined in the
lowCompat.css style sheet to display a 16x16 pixel portion of the
sprite0.png sprite, offset by 16 pixels horizontally. (The file
sprite0.png is the name of the sprite that was auto-generated by the ASP.NET Sprite and Image Optimization Framework.)
The display of the image is handled entirely in CSS. You may wonder, then, why the
<img> element rendered by the ImageSprite control contains an
src attribute and why it's set to the value
What does this do?
Although the bomb image (in this example) is displayed entirely through CSS, it is important that the
<img> element still have an
attribute, as this is a required attribute. The ASP.NET Sprite and Image Optimization Framework could have created a 1x1 transparent image in the
and referenced it here, but that would prompt the browser to send an HTTP request to the server for this blank image. Instead, the ASP.NET Sprite and Image Optimization Framework
uses an inline image here. That gobbledygook is a base-64 encoded string representing a 1x1 transparent PNG image. Granted, a user's browser may not support inline
images, but that doesn't matter because the actual image being displayed is defined in the CSS.
The net result is that the ImageSprite Web control reduces the number of HTTP requests. Previously we needed 12 HTTP requests - one for the web page, two for style sheets,
and nine for the nine images. Using the sprite, we now have five HTTP requests - one for the web page, three for style sheets (the original two style sheets plus
lowCompat.css), and one for the sprite itself.
As we just saw, the ASP.NET Sprite and Image Optimization Framework uses a sprite when visited by Internet Explorer 8 or a version of Firefox prior to version 3.5. But what happens when
visiting with Internet Explorer 9 or Firefox 3.5 or beyond, or Google Chrome, or Apple Safari? In those instances, the ImageSprite Web control uses inline images.
When using inline images, the markup rendered by the ImageSprite control is nearly identical to the markup when using a sprite. The only difference is that instead of
adding a reference to the style sheet
lowCompat.css, when using inline images the
highCompat.css style sheet is referenced instead.
Recall that the classes defined in the
lowCompat.css used the
background-position CSS settings to display a particular chunk of a sprite. In
lowCompat.css, the CSS classes contain the actual content
of the image as a base-64 encoded string. For example, here's the (abbreviated) definition of the
bomb-png class in
Because the images' contents are defined directly within the CSS file, the browser doesn't need to make any requests back to the server to load the images (or a sprite). Consequently, when using inline images the number of HTTP requests drops to four - one for the web page and three for style sheets. There are no requests for image files.
Reducing the number of HTTP requests a browser needs to make to completely load a web page is a common technique used to improve a website's performance. The ASP.NET Sprite and Image Optimization Framework makes it easy to improve your page's load times by combining multiple images into sprites and using inline images. As we saw in this article, the ASP.NET Sprite and Image Optimization Framework can automatically create sprites, generate the CSS and markup for displaying an image from a sprite or using inline images, and can determine which of the two approaches to use based on the user's browser.