ntwo

导航

ASP.NET站点性能提升-减少图片加载时间

缓存

Cache-Control应答头

IIS通过Cache-Control应答头告诉浏览器和代理是否缓存可以图片。它的可能值包括:

Cache-Control value Description
no-cache Prevents caching in the browser or proxies.
private Allows caching in the browser, but not in proxies. This is the default value.
public Allowing caching in both the browser and in proxies.

除了这个, Cache-Control: max-age头指定浏览器缓存图片的最大时间。HTTP 1.1规范建议服务器不要指定这个值超过1年。

如果图片在缓存中,访问者刷新页面(Ctrl + F5),或者图片的max-age过期,浏览器会发送一个条件请求。这个请求有一个If-Modified-Since请求头指出缓存图片的接收时间。如果没有新版本,服务器答复304“Not Modified”。如果有新版本,服务器发送200应答,应答中包括新图片。

阻止条件请求

任何请求都是昂贵的,即使答应是短小的,例如304应答。最好设置max-age为一年。

如果图片修改了,怎么办?访问者要看一年旧图片?为了防止这种情况,可以在图片名中加入版本号,例如:myimage_v2.jpg。当图片更新时,图片更名myimage_v3.jpg。浏览器在缓存中不能找到新图片,就会从服务器上重新获取。

手工更新图片名称会需要很大的工作。使用本文后面介绍的Image control adapter。

Expires头

Expires是在HTTP1.0中定义的。Cache-Control头始终比Expires头优先级高。现在,没有理由再使用Expires。

在IIS 7中配置Cache-Control

  1. 打开IIS Manager。
  2. 单击服务器。然后,在右侧窗口中双击HTTP Reponse Headers。
  3. 单击Add。在Name字段中,输入Cache-Control,在Value字段中,输入public。
  4. 移除X-Powered-By头。因为浏览器或代理都不使用它,所以它只会增加开销。
  5. 点击Set Common Headers。
  6. 设置Expire Web Content。选择After,指定365天。

如果在integrated pipeline模式下使用IIS 7,可以在web.config中加入clientCache达到同样的目的:

<configuration>
...
  <system.webServer>
    <staticContent>
      <clientCache cacheControlCustom="Cache-Control: public"  
        cacheControlMode="UseMaxAge"  
        cacheControlMaxAge="365.00:00:00"/>
    </staticContent>
  </system.webServer>
...
</configuration>

这些设置应用于所有的静态文件,包括JavaScript和CSS文件。

在IIS 6中配置Cache-Control

使用相同的URL引用同一个图片

浏览器和代理根据URL缓存图片。所以,使用的URL引用同一个图片。否则会加载和缓存多个图片。

  • 使用一致的大小写。在URL中全部使用小写是最容易的方法。
  • 如果有多个网站使用共享图片,把共享图片放在共享域中。

从无cookie子域提供图片

当浏览器上设置cookie时,以后浏览器所有的请求都会包括cookie,包括静态内容请求,例如图片、CSS和JavaScript文件。而这种情况会被放大,因为很多访问者使用非对称Internet连接,上传连接的速度要比下载的速度慢。

可以通过在一个单独的子域提供静态内容,消除cookie。当静态文件很多,并且cookie很大时,效果更好。

为新子域创建一个A记录,例如img.mydomain.com。指向网站的IP地址。这样,不需要移动图片。只需要图片的URL。例如,修改:

<img src="/images/picture.jpg" />

为:

<img src="http://img.mydomain.com/images/picture.jpg" />

这会使得HTML有点长。但是,如果对.aspx使用压缩,文件的大小不会相差很多。

如果从根域http://mydomain.com提供内容,而不是http://www.mydomain.com,根域中设置的cookie会发送到子域。在这种情况下,为静态内容注册一个新域,不要注册子域。

并行加载

浏览器并行加载静态文件减少页面加载时间。下图显示一个拥有八个组件的高度简化的瀑布图,所有这些组件从一个域加载:

2011-01-16 20 19 29

在从无cookie子域提供图片,我们可以看到如何节省带宽。

如果使用两个不同的无cookie域,而不是一个,会怎么样?会加倍并行加载的数量:

2011-01-16 20 22 41

浏览器是查找主机名而不是IP地址的。这意味着没有必要移动图片到一个单独的网站。只需要将单独的域名指向网站的IP地址。

在创建很多单独的域加速并行加载前,必须知道对每个域,浏览器需要进行DNS查找,创建连接。后者,可能比加载文件花费更多的时间。创建HTTPS连接尤其昂贵。创建连接的开销与地理距离也有关。例如,如果服务器在美国,访问者在欧洲,开销就会比较高。

通过测试决定域的数量。可能会发现最优的数字会在1到4之间。

新浏览器,例如IE8和Firefox3每个域并行加载6个组件,而不是2个。对于这些浏览器,考虑只使用一个域。

确保在所有的页面上,同一个图片只有一个域。否则,浏览器会看到不同的图片URL,就会缓存图片两次。

解决方案是根据图片URL选择域。例如,如果有两个域,计算图片URL的散列,如果散列是奇数,使用第一个域,否则,使用另一个域。也可以使用文件名的长度或扩展名。

Image control adapter

Image control adapter为Image和Hyperlink控件加入以下特性:

  • 转换图片image为小写。
  • 在图片URL中加入最后修改时间。
  • 使用web.config中设置的无cookie子域替换图片URL中的域。
  • 使用第二无cookie子域加速并行下载。允许排除已经从每个子域并行加载数量超过两个组件的现代浏览器。
  • 移除内联样式border-width:0px;它由ASP.NET3.5和以下自动生成。
using System;
using System.Web;
using System.Web.UI;

using System.Text;
using System.IO;
using System.Web.UI.WebControls.Adapters;
using System.Web.UI.WebControls;
using System.Configuration;
using System.Collections.Specialized;
using System.Web.Caching;

// If parts of your site use https, review this code to make sure it works for you.
// In particular, make sure you don't use non-https image urls on https pages.
//
// web.config has the url rewriter configuration, which translates an image url
// that contains the last modified time back to the original url, so the server
// can serve up the currect image. Look for section <system.webServer>, subsection <rewrite>.
// This web.config needs to sit on the web site(s) that hold the images.
// This definition only works with IIS 7, not IIS 6.

namespace ImageAdapter
{
    public class Adapter : WebControlAdapter
    {
        protected override void RenderBeginTag(HtmlTextWriter writer)
        {
            Image image = Control as Image;
            if (image == null)
            {
                // The control is not an image. Call the base class.
                base.RenderBeginTag(writer);
            }
            else
            {
                string loadsManyImagesConcurrently = 
                    HttpContext.Current.Request.Browser["loadsManyImagesConcurrently"];

                bool useSingleDomain = (loadsManyImagesConcurrently == "true");

                string newImageUrl = NewImageUrl(image.ImageUrl, useSingleDomain);
                image.ImageUrl = newImageUrl;

                // ------
                // Remove border=0 style generated by ASP.NET

                StringBuilder originalHtml = new StringBuilder();
                base.RenderBeginTag(new HtmlTextWriter(new StringWriter(originalHtml)));

                // Get rid of style generated by ASP.NET.
                // If the image is not part of a hyperlink, it will have a style that includes
                // the width and height. If part of a hyperlink, its style will only have border-width:0px.
                originalHtml.Replace("border-width:0px;", "").Replace(" style=\"\"", "");
                writer.Write(originalHtml);
            }
        }

        protected override void RenderEndTag(HtmlTextWriter writer)
        {
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
        }

        private string NewImageUrl(string imageUrl, bool useSingleDomain)
        {
            // If there is no imageUrl, return right away.
            if (string.IsNullOrEmpty(imageUrl))
            {
                return imageUrl;
            }

            // Convert image URL to lower case, so all image URLs have consistent casing.
            string imageUrlLc = this.Control.ResolveUrl(imageUrl).ToLower();

            // Find the path of this image.
            // Return the imageUrl unchanged if the image is not on the current website.
            string path = "";
            if ((!imageUrlLc.StartsWith("http://")) && (!imageUrlLc.StartsWith("https://")))
            {
                // imageUrl is a relative url.
                path = imageUrlLc;
            }
            else
            {
                // imageUrl is an absolute url. 

                Uri imageUri = new Uri(imageUrlLc);

                if (string.Compare(
                        imageUri.Host, 
                        System.Web.HttpContext.Current.Request.Url.Host, 
                        StringComparison.OrdinalIgnoreCase) != 0)
                {
                    // The image sits on another domain (so it is part of another site)
                    // so we can't change the image url.
                    return imageUrl;
                }

                path = imageUri.PathAndQuery;
            }

            // -----------------
            // Insert last update time in the path

            path = InsertStringIntoPath(path, LastUpdateTime(path));

            // -----------------
            // Retrieve web.config settings
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            //string reUserAgentMultiImageDomains = appSettings["reUserAgentMultiImageDomains"];
            string imageSubDomain1 = appSettings["ImageSubDomain1"];
            string imageSubDomain2 = appSettings["ImageSubDomain2"];

            if (string.IsNullOrEmpty(imageSubDomain1) &&
                string.IsNullOrEmpty(imageSubDomain2))
            {
                return path;
            }

            useSingleDomain = useSingleDomain || string.IsNullOrEmpty(imageSubDomain2);

            // -----------------
            // Figure out which subdomain to use. Base on the image's url, so images are associated
            // with same subdomain on every page.
            int imageUrlHash = imageUrlLc.GetHashCode();
            string newDomain =
                ((!useSingleDomain) && (imageUrlHash % 2 != 0)) ?
                imageSubDomain2 : imageSubDomain1;

            return (newDomain + path);
        }

        /// <summary>
        /// Returns the last update time of an image.
        /// </summary>
        /// <param name="path">
        /// Relative url of the image.
        /// </param>
        /// <returns>
        /// Number of seconds since the start of the epoch
        /// module 40,000,000 that the file was last updated.
        /// 40,000,000 seconds is more than a year. By using modulo,
        /// the size of the long is reduced, while it is still 
        /// extremely unlikely that 2 different update times for the
        /// same file result in the same return value.
        /// 
        /// The long is returned as a string, with hexadecimal characters.
        /// It isn't returned as a base64 string, because base64 is case sensitive,
        /// and a browser cache may do case insensitive compares to urls.
        /// 
        /// If the file doesn't exist, "" (empty string) is returned.
        /// </returns>
        private string LastUpdateTime(string path)
        {
            try
            {
                // File.GetLastWriteTime returns 1/01/1601 11:00:00 AM
                // if the file doesn't exist. That corresponds with these ticks:
                const long ticksFileNotExists = 504911628000000000;

                // Cache key prefix. Used when caching the last modified time to 
                // distinguish last modified time cache entry for a file fron any
                // other cache entries for the file.
                const string cacheKeyPrefix = "lmt_";

                // ------------
                // Try to get last modified time from cache

                string cacheKey = cacheKeyPrefix + path;
                Page currentPage = (Page)System.Web.HttpContext.Current.Handler;
                string lastUpdateTimeHex = (string)currentPage.Cache[cacheKey];

                if (lastUpdateTimeHex == null)
                {
                    string filePath = System.Web.HttpContext.Current.Server.MapPath(path);
                    // Get last update time in ticks. 
                    DateTime lastUpdateTime = File.GetLastWriteTime(filePath);
                    long lastUpdateTimeTicks = lastUpdateTime.Ticks;

                    if (lastUpdateTimeTicks == ticksFileNotExists)
                    {
                        lastUpdateTimeHex = "";
                    }
                    else
                    {
                        // Shorted lastUpdateTimeSeconds. Make its units seconds rather than ticks
                        // 1 second = 10,000,000 seconds. And mod by 40000000 - 40000000 seconds
                        // is just over a year, so the same image has to survive over a year on the site
                        // before it could possible get a duplicate last update time inserted in its url.
                        long lastUpdateTimeSeconds = (lastUpdateTimeTicks / 10000000) % 40000000;
                        lastUpdateTimeHex = lastUpdateTimeSeconds.ToString("x");
                    }

                    // Cache the newly found last update time
                    CacheDependency cd = new CacheDependency(filePath);
                    currentPage.Cache.Insert(cacheKey, lastUpdateTimeHex, cd);
                }

                return lastUpdateTimeHex;
            }
            catch
            {
                // Server.MapPath throws an exception when it can't map the path.
                return "";
            }
        }

        /// <summary>
        /// Inserts a string into a path and returns the result.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="s"></param>
        /// <returns>
        /// </returns>
        private string InsertStringIntoPath(string path, string s)
        {
            string extension = Path.GetExtension(path);
            return path.Substring(0, path.Length - extension.Length) + "__" + s + extension;
        }

    }
}

安装步骤:

Installation of ImageAdapter

This manual and the software it describes are part of the book ASP.NET Site Performance Tuneup, ISBN 978-1-849690-68-3, by Matt Perdeck, published by Packt Publishing Limited.

The ImageAdapter makes it easy to implement many of the recommendations in chapter 10 "Reduce Image Load Times". It changes the way the ASP.NET Image and Hyperlink controls generate an img tag:

  • Converts image URL to lowercase.
  • Inserts the last modified time of the image in the image URL.
  • Optionally replaces the domain of the image URL by a cookieless subdomain you set in web.config.
  • Optionally uses a second cookieless subdomain to boost parallel downloads.
  • Allows you to exclude modern browsers that already load more than two components in parallel per domain.
  • Removes inline style “border-width: 0px;” which is automatically generated by ASP.NET.

The installation consists of these steps:

  1. Install the adapter
  2. Install rewrite rules to match incoming image URLs with actual images
  3. Set a cookieless subdomain for use by image URLs
  4. Set a second cookieless subdomain to boost parallel image loading
  5. Prevent newer browsers from using the second cookieless subdomain

1. Install the adapter

First, compile the ImageAdapter project, and add a reference to the generated dll to your Web Site or Web Application.

The adapter is a class Adapter in name space ImageAdapter derived from the Image class. Register the adapter, so all Image controls, and all Hyperlink controls that show an image, use this new class:

  1. Add an App_Browsers folder. If you use a Web Site, right click the Web Site, choose Add ASP.NET Folder, choose App_Browsers.
  2. Right click your new App_Browsers folder, choose Add New Item, and add a Browser file. Give it any name you like.
  3. Enter the code below in the new browser file. This tells ASP.NET that for all browser types (refID="Default"), controls of type System.Web.UI.WebControls.Image now need to be implemented by ImageAdapter.Adapter:
<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.WebControls.Image"
         adapterType="ImageAdapter.Adapter" />
    </controlAdapters>
  </browser>
</browsers>

2. Install rewrite rules to match incoming image URLs with actual images

The adapter inserts the last modified time of the image file in the image URL, in the form of a base64 string. This way, when an image is updated, the browser ignores the old image that it may still have in its cache and requests the updated image. For example, image.png may become image__b0f133.png.

Does that mean that each time the server serves up an image, it accesses the file system to get the last modified time? That would be expensive, so the adapter caches the last modified time in memory. Each cache entry is given a file dependency, so the cache entry is deleted when the file is changed. That in turn causes the server to get the latest last modified time. File dependencies are described in chapter 3 "Caching".

When the browser requests an image, the image URL it sends will have the last modified time (inserted by the adapter). That last modified time needs to be removed from the image URL by IIS to match it to the actual image on disk. To make that happen, follow these steps:

  1. Install the URL Rewriting module for IIS 7. Download at http://www.iis.net/download/URLRewrite.
  2. Add the following definition to web.config. This rewrites incoming image URLs with a .png, .jpg or .gif extension back to the original image file name.
<configuration>
...  
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="last updated time">
          <match url="(.*)__.*\.(png|jpg|gif)" />
          <action type="Rewrite" url="{R:1}.{R:2}" />
        </rule>
      </rules>
    </rewrite>

  </system.webServer>
...  
</configuration>
The <match> element matches incoming URLs against the regular expression (.*)__.*\.(png|jpg|gif). The parts in between brackets (shown in red) are groups. Those groups correspond with {R:1} and {R:2} in the <action> element.

The first group corresponds with all characters in the URL before the __ that was inserted by the adapter. The second group corresponds with the extension (png, jpg or gif). Together, they make up the image URL, but without the inserted last modified time. The <action> element simply tells IIS 7 to put the two groups together, to arrive at an image URL that actually matches the image.

If your site uses cookies, redirect all visitors who arrive via your base domain or ip address to your www subdomain. This is because cookies are domain specific - if someone visits www.mydomain.com and receives a cookie, that cookie won't be recognized by their browser on a subsequent visit to mydomain.com. Remember that Session state and the Authorization functionality (user logins) all use cookies.

You can implement this by adding the rewrite rule below (in red) to your web.config. This rule permanently redirects a visitor to http://www.mydomain.com unless the visitor is already at http://www.mydomain.com, or at http://img1.mydomain.com or http://img2.mydomain.com. So if someone visits http://mydomain.com/file.aspx, they are redirected to http://www.mydomain.com/file.aspx. This only works with IIS 7 in integrated pipeline mode, not in IIS 6 or IIS 7 in classic pipeline mode.

<configuration>
...  
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="CanonicalHostNameRule1">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTP_HOST}" pattern="^www.mydomain.com$" negate="true" />
            <add input="{HTTP_HOST}" pattern="^img1.mydomain.com$" negate="true" />
            <add input="{HTTP_HOST}" pattern="^img2.mydomain.com$" negate="true" />
          </conditions>
          <action type="Redirect" url="http://www.mydomain.com/{R:1}" />
        </rule>

        <rule name="last updated time">
          <match url="(.*)__.*\.(png|jpg|gif)" />
          <action type="Rewrite" url="{R:1}.{R:2}" />
        </rule>
      </rules>
    </rewrite>

  </system.webServer>
...  
</configuration>

3. Set a cookieless subdomain for use by image URLs

To serve your images from for example subdomain img1.mydomain.com, first log into your domain registrar and create an A record for the img1 subdomain. Then make sure that the adapter modifies every image URL so it uses that subdomain, by adding key ImageSubDomain1 to the appSettings in web.config:

<configuration>
...  
  <appSettings>
    <add key="ImageSubDomain1" value="http://img1.mydomain.com"/>
  </appSettings>
...  
</configuration>

4. Set a second cookieless subdomain to boost parallel image loading

You can serve the images from two subdomains, to boost parallel loading. To do so, add a key ImageSubDomain2 with the second subdomain. The adapter doesn't support adding a third or fourth subdomain.

<configuration>
...  
  <appSettings>
    <add key="ImageSubDomain1" value="http://img1.mydomain.com"/>
    <add key="ImageSubDomain2" value="http://img2.mydomain.com"/>
  </appSettings>
...  
</configuration>

5. Prevent newer browsers from using the second cookieless subdomain

Newer browsers such as Internet Explorer 8 and Firefox 3 load 6 images in parallel per domain rather than 2. With these browsers, the DNS and connection overhead associated with the second subdomain may not be worth it.

ASP.NET stores a list of browser properties, that it uses when generating the html for a control. To allow you to prevent use of the second subdomain by particular browsers, the adapter introduces a new browser property,  loadsManyImagesConcurrently. If set to "true" for a browser, the adapter uses only the first subdomain when generating image URLs for a page that will go to that browser. If set to "false" or if not set at all, the adapter uses both subdomains (provided you specified 2 subdomains).

To set loadsManyImagesConcurrently to "true" for Internet Explorer 8 and 9, and for Firefox 3 and higher, use the following code (in red) in the browser file you inserted in the App_Browsers folder in step 1:

<browsers>
  <browser id="IE8up" parentID="IE6to9">
    <identification>
      <capability name="majorversion" nonMatch="^[1-7]" />
    </identification>
    <capabilities>
      <capability name="loadsManyImagesConcurrently" value="true" />
    </capabilities>
  </browser>
  
  <browser id="FF3up" parentID="MozillaFirefox">
    <identification>
      <capability name="majorversion" nonMatch="^[1-2]" />
    </identification>
    <capabilities>
      <capability name="loadsManyImagesConcurrently" value="true" />
    </capabilities>
  </browser>

  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.WebControls.Image"
         adapterType="ImageAdapter.Adapter" />
    </controlAdapters>
  </browser>
</browsers>

In chapter 3 "Caching", you saw how to cache a page on the server, and how to cache different versions of the page. If you use 2 subdomains for some browsers and 1 for others, be sure to cache a version for each type of browser.

Conditions of use

  • You are free to use and distribute these instructions and the related software.
  • If you distribute the software, you agree to distribute the instructions in unaltered form with the software (including these conditions of use), unless you have specific permission by the author to do otherwise.
  • You agree that your use of these instructions and the related software is at your own risk. There is no guarantee that they are fit for any particular purpose.
  • These conditions will be governed by the laws current in the state of NSW, Australia. Only courts in NSW, Australia will have jurisdiction over these conditions of use.
  • By using or distributing these instructions or the related software, you agree to these conditions of use.

图片大小

使用合适的图片格式

大多数浏览器可以支持最少三种主要图片格式:JPEG、GIF和PNG。每一种图片格式都以压缩形式存储图片。

Format Compression Supports Transparency Supports Animation
JPEG Lossy: Sacrifices image quality for better compression. Optimized for smooth color transitions, millions of colors. Produces artifacts around sharp transitions of color. No No
PNG Nonlossy: No loss of quality. Compresses better than GIF, except for tiny images. Yes* No
GIF Nonlossy: Allows no more than 256 different colors per image.** Yes*** Yes

*Supports semi-transparency; for example, you can make a pixel 50 percent transparent.

**Each individual color can be chosen from a palette of 16,777,216 colors.

***Only binary transparency is supported; a pixel is either 100 percent transparent or not at all.

PNG格式有三个不同的版本:

PNG Version Description
PNG8 Allows no more than 256 different color / transparency combinations per image. When setting a color / transparency combination, you can choosen from 16,777,216 colors and 256 transparency levels (between no transparency at all and full transparency).
PNG24 Allows 16,777,216 different colors for each pixel, but with no transparency.
PNG32 Allows 16,777,216 different colors, and 256 transparency levels per pixel.
Internet Explorer 6 gives transparent pixels in PNG32 image a background color.

注意,无论是PNG8、PNG24或PNG32,它们的扩展名都是.png。当以PNG格式保存图片时,图像编辑程序会根据图片的色深选择合适的版本。

为了减少图片大小,为以下类型的图片选择合适的格式:

Type of image Preferred format
Photos JPEG
Graphics, cartoons, graphs PNG
Tiny graphics, such as bullet points GIF
Animated progress images GIF

避免在HTML缩小图片

HTML允许指定图片比实际尺大小的尺寸。例如:

<img src="physically200by200.png" width="100" height="100" />

如果页面上有第二个img标签显示完整的图片,这样做是有意义的。否则,最好将图片调整为实际需要的大小。

工具

有很多免费的命令行工具进行批量图片格式转换、减少文件大小。

PNGOUT

http://advsys.net/ken/utils.htm

这个工具将图片从GIF转换为PNG。通常使得文件更小。例如:

pngout input.gif output.png

将一个目录中的所有GIF图片:

for %i in (*.gif) do pngout "%i"

pngout也可以减小PNG图片的大小:

for %i in (*.gif) do pngout "%i"

Pngcrush

http://pmt.sourceforge.net/pngcrush/

pngcrush减小PNG图片文件的大小。它比pngout快,但效果要差一些。例如:

pngcrush.exe -rem alla -reduce -brute input.png output.png

Jpegtran

http://jpegclub.org/

Jpeg从JPEG图片中删除所有的元数据,例如版权信息。它减小文件大小,而不影响图片质量。例如:

jpegtran -copy none -optimize input.jpg output.jpg

NConvert

http://www.softpedia.com/get/Multimedia/Graphic/Image-Convertors/Nconvert.shtml

这个一个免费的图片转换程序,支持超过500种图片格式。例如:压缩文件到原来75的质量:

nconvert.exe -q 75 -o output.jpg input.jpg

将目录中的所有图片压缩版本写到一个compressed子目录:

for %i in (*.jpg) do nconvert.exe -q 75 -o compressed\%i %i

ImageMagic

http://www.imagemagick.org/script/index.php

ImageMagic是一个由多个程序组成的包,允许你转换图片,查看它们的属性。它有上百个功能。例如,将一个图片转换成缩略图,不宽于100像素,不高于200像素,并保持原来的长宽比:

convert -resize 100x200 input.jpg output.jpg

组合图片

Web经常包含很多小图片,它们必须由浏览器分别下载。这产生了很多额外的开销。有一种方法可以组合多个图片到单个图片中,这个技术就是CSS Spites。

考虑以下的HTML:

<img src="geography.png" width="38" height="48" />
<p>some html ...</p>
<img src="chemistry.png" width="28" height="46" />
<p>some html ...</p>
<img src="maths.png" width="46" height="45" />

这段HTML使得浏览器发送3次请求,一次下载一个图片。使用CSS Spites可以只用一次请求。

首先,将三个图片组合成一个图片:

2011-01-18 13 39 35

使用HTML:

<div style="width:38px; height:48px; background: url(combined.png)  
  0px 0px">
</div>
<p>some html ...</p>
<div style="width:28px; height:46px; background: url(combined.png)  
  -38px 0px">
</div>
<p>some html ...</p>
<div style="width:46px; height:45px; background: url(combined.png)  
  -66px 0px">
</div>

可以在线创建组合图片和CSS的工具:

微软发布了一个ImageSprite自定义控件组合图片并生成需要的CSS,这样当改变图片时,就不用再组合图片并修改CSS了。

避免使用图片

CSS中的圆角

很多浏览器本身已经支持圆角。Fixfox使用moz-border-radius css属性,而Google Chrome支持CSS3的 border-radius属性。IE9也支持border-radius,但之前的IE不支持。

不需要特殊浏览器实现圆角:

<div>
  <div class="r15"></div>
  <div class="r13"></div>
  <div class="r12"></div>
  <div class="r21"></div>
  <div class="content">
    Rounded corners without anti-alia
  </div>
  <div class="r21"></div>
  <div class="r12"></div>
  <div class="r13"></div>
  <div class="r15"></div>
</div>

CSS:

.r15, .r13, .r12, .r21
{ overflow:hidden; background-color: #c0c0c0; }
.r15 { height: 1px; margin: 0 5px; }
.r13 { height: 1px;  margin: 0 3px; }
.r12 { height: 1px; margin: 0 2px; }
.r21 { height: 2px; margin: 0 1px; }

加入额外的像素:

.r15, .r13, .r12, .r21
{
  overflow:hidden; background-color: #c0c0c0; 
  border-color: #e0e0e0; border-style: solid; 
}
.r15 { height: 1px; border-width: 0 2px; margin: 0 3px; }
.r13 { height: 1px; border-width: 0 1px; margin: 0 2px; }
.r12 { height: 1px; border-width: 0 1px; margin: 0 1px; }
.r21 { height: 2px; border-width: 0 1px; margin: 0 0; }

为了不加入额外的HTML,给每个有圆角的盒子添加一个类,然后使用JavaScript代码查找这些盒子,在DOM中添加额外的行。

有很多jQuery插件可以实现这个功能。在http://plugins.jquery.com中搜索。如果不使用jQuery,也有其它的选择:

工具符号

网页上经常包含小的工具符号,例如电话和箭头:

2011-01-24 10 33 15

并不是所有的浏览器都支持所有的Unicode符号。在使用前,检查访问者的浏览器是否支持。

参考:

快捷图标

快捷图标,是浏览器显示在网站地址旁边的图标。即使没指定快捷图标,浏览器会始终试图使用它。所以,如果图标没有在浏览器缓存中,浏览器每次打开网站的页面时,都会请求快捷图标。

指定图标的一个方法是将图标命名为favicon.ico,将它放到网站的根目录。但是,如果修改了图标,所有访问者的缓存中还保存着旧图标,所以还会看到旧图标。

一个更好的方法是在每个页面的head中显式链接快捷图标。这样,就可以指定图标名和位置。例如:

<head runat="server">
    <link rel="icon" href="shortcut_v1.ico" />
</head>

如果使用无cookie子域:

<head runat="server">
    <link rel="icon" href="http://img1.mydomain.com/shortcut_v1.ico" />
</head>

这样,当决定更换快捷图标时,可以给图标一个新的名称,例如shortcut_v2.ico,使浏览器请求新版本。

内容发布网络

在其它情况相同的情况下,web服务器越近,响应请求的速度越快。所以,可以将静态内容部署到内容发布网络(Content Delivery Network)上。这是个由服务器缓存的全球性网络,它会将请求路由到离访问者最近的服务器。

如果预算有限,可以使用以下低成本提供商:

更多资源

posted on 2011-01-24 11:19  9527  阅读(2772)  评论(2编辑  收藏  举报