Generate CSS sprites and thumbnail images on the fly in ASP.NET sites - part 2

by Matt Perdeck 14. September 2011 20:58

This Series

Introduction

This is part 2 of a 3 part series about the ASP.NET CSS Sprite Generator package. It allows you to compress and resize the images in your ASP.NET web site on the fly, and to combine them into sprites. Simply add the ASP.NET CSS Sprite Generator dll and configure the package in your web.config - no need to change the site itself.

Contents

Part 1

Part 2

Part 3

Configuration

Configuration for the package fall in three categories:

  • Overall Configuration - settings that apply to the package as a whole, such as whether it is active or not, whether it processes page images, etc.
  • Image Groups - determine which images are processed and how. You've already come across groups in the quick start section.
  • cssImages elements - tell the package which CSS background images to process, and set restrictions on how they can be combined into sprites to cater for repeating background images.

These categories are discussed in the following sections.

Overall Configuration

The package supports these package wide configuration settings:

Overall Switches

Image Gathering

Options that determine how the package finds the images to be processed

Sprite Generation

Options that determine how the package generates sprites


Overall Switches


active

Determines when the package is active. When it is not active, it doesn't affect your site at all and none of the other attributes or child elements listed in this section have any effect.

Value Description
Never Package is never active, irrespective of debug mode
Always Package is always active, irrespective of debug mode
ReleaseModeOnly
(default)
Package is only active in Release mode
DebugModeOnly Package is only active in Debug mode

Example

<cssSpriteGenerator active="Always" >
    ...
</cssSpriteGenerator>

Whether your site is in Debug or Release mode depends on the debug attribute of the compilation element in your web.config file. If that attribute is set to false, your site is in Release mode (as it should be when live). When it is set true, it is in Debug mode (as it should be in development). It looks like this in web.config:

<configuration>
    ...
    <system.web>
        <compilation debug="true">
            ...
        </compilation>
        ...
    </system.web>
    ...
</configuration>

By default, the package is only active in Release mode - so you won't see any effect while you're developing. To ensure that the package is active in both Release mode and in Debug mode, set active to Always, as shown in the example above.

Note that the active property acts as a master switch for the whole package. If it isn't active, none of the other properties have any effect.

exceptionOnMissingFile

Determines whether the package throws an exception when an image file is missing.

Value Description
Never
(default)
The package never throws an exception when an image file is missing.
Always The package always throws an exception when an image file is missing.
ReleaseModeOnly The package only throws an exception if the site is in Release mode.
DebugModeOnly The package only throws an exception if the site is in Debug mode.

Example

<cssSpriteGenerator exceptionOnMissingFile="DebugModeOnly" ... >
    ...
</cssSpriteGenerator>

In order to process an image, the package has to actually read that image. What happens if the image file cannot be found on the web server? That is determined by the exceptionOnMissingFile attribute:

  • If exceptionOnMissingFile is active (see table above) and the package finds that an image file cannot be found, it throws an exception with the path of the image. That makes it easier to find missing images.
  • If exceptionOnMissingFile is not active, the package doesn't throw an exception and recovers by not processing the image. For example, if the image was found via a img tag, it will leave the tag alone.

If all images should be present in your development environment, than it makes sense to set exceptionOnMissingFile to DebugModeOnly. That way, you quickly find broken images while developing your site, while preventing exceptions in your live site where you probably prefer a broken image over an exception.

Keep in mind that if you want exceptions while the site is in Debug mode, you have to ensure that the package is actually active in Debug mode - set active to Always to make that happen.


Image Gathering


processPageImages

Determines whether images on the current page are processed

Value Description
Never Images on the current page are never processed
Always
(default)
Images on the current page are always processed
ReleaseModeOnly Images on the current page are processed if the site is in Release mode.
DebugModeOnly Images on the current page are processed if the site is in Debug mode.

Example

<cssSpriteGenerator processPageImages="Never" ... >
</cssSpriteGenerator>

Normally when a page on your site opens, the package finds all the img tags on the page, assigns them to image groups and processes the groups into sprites. It then replaces the img tags with div tags that show that part of the sprite matching the original image - so your page still looks the same but loads quicker (details).

When you switch off processPageImages, the package no longer goes through the page looking for img tags. It also won't replace any img tags.

You would switch processPageImages off if you only wanted to process CSS background images.

processCssImages

Determines whether the CSS background images listed in cssImages are processed

Value Description
Never CSS background images are never processed
Always
(default)
CSS background images are always processed
ReleaseModeOnly CSS background images are processed if the site is in Release mode.
DebugModeOnly CSS background images are processed if the site is in Debug mode.

Example

<cssSpriteGenerator processCssImages="Never" ... >
</cssSpriteGenerator>

If this option is active (the default), than the CSS background images you've listed in the cssImages element are processed by the package.

processFolderImages

Determines whether images stored in one or more folders on the web server are processed. See the sample web site DemoSite_FolderImages in the downloaded solution.

Value Description
Never
(default)
The package never processes images from folders on the web server
Always The package always processes images from folders on the web server
ReleaseModeOnly The package only processes images from folders on the web server if the site is in Release mode
DebugModeOnly The package only processes images from folders on the web server if the site is in Debug mode

Example

<cssSpriteGenerator processFolderImages="Always" ... >
</cssSpriteGenerator>

In addition to having the package find images on the current web page (if processPageImages is active) and from the cssImages element (if processCssImages is active), you can also get it to find images from one or more folders on the web server.

Why would you want to add images to a sprite that are not actually on the page? Take a very simple web site that uses 3 small icons on its pages, but not all icons appear on all pages:

PageIcons used
default.aspxcontactus.png, cart.png, print.png
contactus.aspxcart.png, print.png
cart.aspxcontactus.png, print.png

If you had the package only read images from the current web page, than it would create different sprites for each page, because each page has a different set of icons. However, it would be far more efficient to have all 3 icons in the one sprite. That way, when a visitor moves from one page to the other, that single sprite is still in browser cache, so doesn't have to be loaded again over the Internet. The way to do that is to get the package to read all icons when it creates a sprite, not just the ones that are on the current web page.

To get the package to find images from one or more folders on the web server, set processFolderImages active. You then also need to set imageFolderPathMatch to determine specifically which images should be read.

Just as with images taken from the current web page and from the cssImages elements, images taken from one or more folders are first assigned to image groups. Only images assigned to a group can become part of a sprite.

This means that if you want to add particular images to a sprite even if they are not on the current web page and not in the cssImages element, you have to take these steps:

  1. Set processFolderImages active;
  2. Make sure that the file paths of the desired images match imageFolderPathMatch;
  3. Make sure that the images match a group, so they can be worked into a sprite. The images taken from folders do not all have to match the same group.

For example, if you have a folder images\icons with .png and .gif images and you want all those images to be made into a sprite irrespective of whether they appeared on the current page, you could use:

<!--switch on processing of images from web server folders, but only process those 
that are in images\icons and that end in .png or .gif-->
<cssSpriteGenerator processFolderImages="Always" 
imageFolderPathMatch="\\images\\icons\\.*?(png|gif)$" ... >
      <imageGroups>
          ...
          <!--add .png images that live in images\icons to this group-->
          <add groupName="icons" filePathMatch="\\images\\icons\\.*?png$" />

          <!--add .gif images that live in images\icons to this second group-->
          <add groupName="icons" filePathMatch="\\images\\icons\\.*?gif$" />
      </imageGroups>
</cssSpriteGenerator>

imageFolderPathMatch

If the processFolderImages property is active, than this property is required. It determines which image files are read.

Type Default
string
(regular expression)
none

Example

<cssSpriteGenerator imageFolderPathMatch="\\images\\img1" ... >
</cssSpriteGenerator>

For details on the folder images feature, see processFolderImages.

The imageFolderPathMatch property is a regular expression. If processFolderImages is active, than the package looks at the file paths of all .png, .gif and .jpg files in the root directory of the site and its subdirectories. Those image files whose paths match imageFolderPathMatch will be processed.

For example, to process all image files in directory images\img1, you would use:

<!--all images in images\img1-->
<cssSpriteGenerator imageFolderPathMatch="\\images\\img1\\" ... >
</cssSpriteGenerator>

(it uses double backslashes because the backslash is a special character in regular expressions, so needs to be escaped with another backslash)

If you wanted to process only the .png files in directory images\img1, you would use:

<!--all .png images in images\img1-->
<cssSpriteGenerator imageFolderPathMatch="\\images\\img1\\.*?png$" ... >
</cssSpriteGenerator>

If you want to process all image files in the root directory of the site and its subdirectories, use:

<!--all images in the site-->
<cssSpriteGenerator imageFolderPathMatch="\\" ... >
</cssSpriteGenerator>

If your site writes images to the root directory of the site or one of its sub directories (for example if visitors can upload images), than make sure that those images are stored in a directory that isn't matched by imageFolderPathMatch, otherwise they could wind up in sprites. Those sprites would get bigger with every image added.

Additionally, if your site writes images frequently, such as more than once every 5 minutes, consider storing these images outside the root directory of the site. For faster processing, the package keeps the structure of the root directory and its sub directories in cache. Each time an image is added to the root directory or one of its sub directories, that cache entry is removed to ensure it isn't outdated, meaning that the package has to rebuild that cache entry again.


Sprite Generation


copiedImgAttributes

Determines which attributes are copied over from an img tag when it is replaced by a div tag.

Type Default
string
(regular expression)
all attributes copied
(except the ones listed below)

Example

<cssSpriteGenerator copiedImgAttributes="onclick|id" ... >
</cssSpriteGenerator>

When the package replaces an img tag with a div tag, it copies over the attributes you had included with the img (with some exceptions, see below). For example, if you had:

<img id="..." onclick="..." onmouseout="..." ... />

That will be replaced with:

<div id="..." onclick="..." onmouseout="..." ... ></div>

Normally, this is what you want. But if it isn't, you can prevent certain attributes from being copied over through the copiedImgAttributes property. That property is interpreted as a regular expression. When you specify copiedImgAttributes, only those attributes that match the regular expression will be copied over (with some exceptions).

This means that if your img tag looks like this:

<img id="..." onclick="..." onmouseout="..." ... />

And you specified a copiedImgAttributes that only matches id and onclick but not onmouseout:

<cssSpriteGenerator copiedImgAttributes="id|onclick" ... >
</cssSpriteGenerator>

Than the resulting div tag will only have the id and onclick attributes:

<div id="..." onclick="..." ... ></div>

Keep in mind that if you don't specify copiedImgAttributes at all, all attributes (with some exceptions) will be copied over.

Exceptions

The package gives special treatment to some attributes:

  • src is used by the img tag to load the image, but this is now done via CSS, so it is never copied over.
  • width and height are set by the package itself.
  • alt is used as the contents of the span or div tag that replaces the img tag (details).
  • class and style are copied over. But if the package generates an additional class name than it gets added to any class attribute you already had on the img tag (it will create a new class attribute if needed). Similar story with any style elements generated by the package.

inlineSpriteStyles

Determines whether the styling needed with the div tags that replace the img tags is inline or in a separate .css file.

Value Description
falseAdditional styling is placed in a separate .css file
true
(default)
Additional styling is inline

Example

<cssSpriteGenerator inlineSpriteStyles="false" ... >
</cssSpriteGenerator>

In the section about how sprites work, you saw how the div tags that replace your img tags use additional styling to show the correct area of the sprite - using background, width, height, etc.

If you leave inlineSpriteStyles at true, the package inlines all the additional styling. That gives you div tags such as this:

<div style="width: 32px; height: 32px; 
  background: url(/TestSite/___spritegen/2-0-0-90- ... -53.png) -200px -0px; 
  display:inline-block;"
  ></div>

However, if you set inlineSpriteStyles to false, the additional styling is placed in a separate .css file which is generated in the same directory as the sprite images themselves. The generated div tags will refer to the styling via CSS classes. This gives you div tags such as this:

<div class="c0___spritegen" >&nbsp;</div>

In that case, make sure that the head tags of your pages have runat="server", so the package can add a link tag for the .css file to the head section:

<head runat="server">

Here are the advantages/disadvantages of setting inlineSpriteStyles to false:

  • The advantage of using a separate .css file is that the next time the page is loaded, the .css file may still be in browser cache - so all that additional styling doesn't have to be loaded over the Internet. This would apply if your visitors tend to hang around on your site, hitting several pages in the one visit.
  • The drawback of using a separate .css file is that if that file is not in browser cache, the browser has one more file to load. Also, if your web server uses compression, the additional inlined styles don't add much to the number of bytes going over the Internet because they are highly compressible.

There are a few cases where it may make sense to place the additional CSS in a separate CSS file by setting inlineSpriteStyles to false:

  • You're pretty sure that on many visits the separate CSS file will be in browser cache.
  • You use the cssImages element to process CSS background images. In that case, the package always generates a separate CSS file with styles that override existing CSS styles to make them work with the new sprites. If you now set inlineSpriteStyles to false, the additional CSS for the div tags will go into the same CSS file as the CSS for the background images, rather than a separate CSS file. This means you've reduced the size of your .aspx pages by taking out the inlined styles, without incurring an additional CSS file load.
  • You use the Combine And Minify package to combine and minify CSS and JavaScript files on your site. In that case, Combine And Minify can combine the separate CSS file with the other CSS files, so you don't incur the extra CSS file load.

generatedFolder

Sets the folder where the generated .css file (if there is one) and the sprites are stored.

Type Default
string___spritegen

Example

<cssSpriteGenerator generatedFolder="generated\sprites" ... >
</cssSpriteGenerator>

This folder will be created (if it doesn't already exist) in the root folder of the site.

You can include one or more \ in this property. In that case, you'll get a folder and one or more subfolders.

classPostfix

Postfix used to ensure that generated class names are unique.

Type Default
string___spritegen

Example

<cssSpriteGenerator classPostfix="___generated" ... >
</cssSpriteGenerator>

If you set inlineSpriteStyles to false, the package generates a .css file with the additional CSS needed to make the sprites work. To make sure that the names of the generated CSS classes do not clash with the other CSS classes in your site, the contents of classPostfix is appended to the generated class names.

If you find that the names of the generated CSS classes clash with the names of other CSS classes in your site, you can change classPostfix to fix this.

Conclusion

This was part 2 of this 3 part series. In part 3 we'll find out about Image Groups, which allow you to manipulate your images on the fly, select images for inclusion into sprites, etc. We'll also go into handling of CSS background images.

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

Books

Book: ASP.NET Site Performance Secrets

ASP.NET Site Performance Secrets

By Matt Perdeck

Details and Purchase

About Matt Perdeck

Matt Perdeck PresentingMatt has written extensively on .Net and client side software development.

more >>