<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>岁月如歌 &#187; background</title>
	<atom:link href="http://lifesinger.org/blog/tag/background/feed/" rel="self" type="application/rss+xml" />
	<link>http://lifesinger.org/blog</link>
	<description>关注用户体验、前端开发，记录生活点滴、岁月足迹。</description>
	<lastBuildDate>Mon, 06 Sep 2010 15:05:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>图片的HTTP请求（续）</title>
		<link>http://lifesinger.org/blog/2009/05/img-http-request2/</link>
		<comments>http://lifesinger.org/blog/2009/05/img-http-request2/#comments</comments>
		<pubDate>Sat, 16 May 2009 11:38:25 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[开发]]></category>
		<category><![CDATA[background]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[flicker]]></category>
		<category><![CDATA[http request]]></category>
		<category><![CDATA[image]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=1681</guid>
		<description><![CDATA[在上一篇中，很多朋友在回复中提到了一些更有意思的现象，忍不住继续挖掘一番： 10. IE6下的背景闪烁bug 这个bug久闻其名，但我自己从来没遇到过。纳闷了许久，后来才发现，这是一个非典型性甚至可以忽略的bug. 因为它的触发条件离普通用户很远： The cause of flickering is choosing &#8220;Every visit to page&#8221; in Tools » Internet Options&#8230; » Temporary Internet Files » Settings&#8230; Selecting anything other than &#8220;Every visit to page&#8221; will fix all flickering. Fortunately, the means that the flicker problem plagues developers far more than your common user. 只有IE的缓存选项设置为“Every visit [...]]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://lifesinger.org/blog/?p=1661">上一篇</a>中，很多朋友在回复中提到了一些更有意思的现象，忍不住继续挖掘一番：</p>
<h3>10. IE6下的背景闪烁bug</h3>
<p>这个bug久闻其名，但我自己从来没遇到过。纳闷了许久，后来才发现，这是一个非典型性甚至可以忽略的bug. 因为它的触发条件离普通用户很远：</p>
<blockquote><p>
 The cause of flickering is choosing &#8220;Every visit to page&#8221; in Tools » Internet Options&#8230; » Temporary Internet Files » Settings&#8230;</p>
<p>Selecting anything other than &#8220;Every visit to page&#8221; will fix all flickering. Fortunately, the means that the flicker problem plagues developers far more than your common user.
</p></blockquote>
<p>只有IE的缓存选项设置为“Every visit to page”时，才会触发。普通用户的默认设置是“Automatically”, 不会遇到此问题。因此继续往下阅读之前<span id="more-1681"></span>，请确保IE6的缓存设置为“Every visit to page”, 否则你将看不到神奇的现象。</p>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_11.html">test_11.html</a></p>
<pre>
&lt;style type="text/css"&gt;
    a { background: #f00 url(square.gif) }
&lt;/style&gt;
&lt;a href="#"&gt;test link&lt;/a&gt;
</pre>
<p>上面的代码平淡无奇，但在IE6下，当鼠标划过test link时，背景会瞬间变红。如果你看不到此现象，请用老虎钳将网线剪掉一半，降低网速后再测试。</p>
<p>除了给链接A设置背景色，还有一些其它触发条件，详细资料请参阅：<a href="http://www.fivesevensix.com/studies/ie6flicker/">Minimize Flickering CSS Background Images in IE6</a>.</p>
<p>注意：只有IE6下，设置“Every visit to page”, 并且给元素A设置了背景色等条件下，才会触发此bug. 上面引用的文章中提到三种解决办法：1. 调整服务器的配置，2. 双缓冲背景，3. js解决办法：</p>
<pre>
try {document.execCommand("BackgroundImageCache", false, true);}catch(e){};
</pre>
<p>到此，似乎已经尘埃落定。但是，好奇虽然害死猫，却也能发现猫世界里的更多秘密：<br />
<img src="http://lifesinger.org/lab/2009/imghttp/imghttp_11.png" alt="imghttp_11.png" /><br />
上图是用Fiddler监控鼠标在链接A上移进移出时的HTTP请求。虽然请求的结果是304（Not modified），但从发送请求到服务器返回304，依旧是需要时间的。在这个时间差里，链接A的背景是红色的，而不是图片。<strong>多余的HTTP请求才是背景闪烁的真正原因</strong>。</p>
<p>明白了这一点，可以看出“双缓冲背景”法，是治标不治本，是视觉上的小hack，并没有减少无谓的HTTP请求。采用调整服务器配置或execCommand hack，才能彻底杜绝多余的HTTP请求。</p>
<p>微软很委婉在一个hotfix中提到这个bug：<a href="http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B823727">Available memory decreases when you view a Web page in Internet Explorer 6 Service Pack 1</a>. 当script中频繁改变一个设置了背景图的按钮的背景色时，会造成IE内存泄漏。微软的文档太文档了，Resolution那一段，我反复读了好几次，才明白微软要表达什么意思，囧。</p>
<p>鉴于目前很多公司的图片服务器配置里已经自动fix了此bug，以及IE6的逐步淡出，还有触发条件离普通用户较远，我们可以逐步忘掉此bug了，就像我们逐步淡忘掉ie 5.5的很多css hack一样。</p>
<p>休息一下，上面只是引子，精彩内容在下面。</p>
<h3>11. 切换class时，背景图的请求</h3>
<p>链接的hover状态切换, 是class切换一个特例。更一般性的测试如下：</p>
<pre>
&lt;style type="text/css"&gt;
    .test1 { background: url(1.jpg) }
    .test2 { background: url(2.jpg) }
&lt;/style&gt;
&lt;div class="test1" id="J_Test">test&lt;/div&gt;
&lt;a href="#" id="J_Link">切换className&lt;/a&gt;
&lt;script type="text/javascript"&gt;
    document.getElementById('J_Link').onclick = function() {
        var el = document.getElementById('J_Test');
        el.className = (el.className == 'test1') ? 'test2' : 'test1';
        return true;
    };
&lt;/script&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_10.html">test_10.html</a></p>
<p>结论：当快速点击“切换className”时，除了IE，其它浏览器都只会产生两次请求。但在IE（包括IE8）中，用Fiddler能捕捉到如下请求：<br />
<img src="http://lifesinger.org/lab/2009/imghttp/imghttp_10.png" alt="imghttp_10.png" /><br />
带红色停止标志的，是Aborted Session. 也就是说，在IE下，当一张图片未下载完成时，如果class就已经切换，正在下载的图片会被中止掉。被中止掉的图片，下次用到时，会再次发送请求。直到图片成功下载后，切换class时才不会再次请求图片。</p>
<p>注意：如果你的观察结果和上面的结论有异，请检查 Internet Options&#8230; » Temporary Internet Files » Settings&#8230; 没有选中&#8221;Every visit to page&#8221;, 以及Fiddler中没有禁用Cache. 否则图片下载完成后，依旧会重新发送请求。如果观察不到请求，请清空IE缓存后再测试。另外，一定要记得用老虎钳剪掉一半网线。</p>
<p>可以看出，<strong>即便在IE8下，当网速较慢时，快速切换某个元素的class，依旧会造成闪烁</strong>。要一直到背景图片下载完成后，才不会闪烁。</p>
<p>知道了问题所在，解决办法就很容易想到了：采用Sprite技术，切换class时只改变<code>background-position</code>.<br />
测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_10.html">test_10b.html</a><br />
注意：用Sprite合成一张图片后，你点得再快，IE也始终只发送一个图片请求。</p>
<p>很想结束本文了，无奈IE下还有一个更诡异的闪烁现象&#8230; Come on~</p>
<h3>12. 神秘的闪烁</h3>
<p>直奔测试页面：<a href="http://lifesinger.org/lab/2009/imghttp/test_12.html">test_12.html</a></p>
<p>第一行星星，当鼠标每次悬浮上去，都会产生一个图片请求：<br />
<img src="http://lifesinger.org/lab/2009/imghttp/imghttp_12.png" alt="imghttp_12.png" /></p>
<p>原来老怀疑JS写法有问题，琢磨了许久，才注意到上图中Caching栏的值：<code>public Expires: Sat, May 2009 04:59:57 GMT</code>. 超级汗googlepages的设置。</p>
<p>再来看第二行星星，悬浮时，没有第一行星星的问题。从Fiddler中可以看出，第二行星星的背景文件也是过期的，为什么却不重新下载呢？</p>
<p>相信你已经留意到测试页面左下角那颗孤零零的星星，这就是第二行星星正常的救星。</p>
<p>根据上面的现象，我们可以猜测IE请求图片的虚拟过程为：</p>
<ol>
<li>需求：改变classA, 需要背景图imgA.</li>
<li>在页面中寻找是否已经有元素使用imgA, 有的话，直接共用。</li>
<li>在缓存中找到了imgA，判断Expire头，如果过期了，则重新发送请求，全新下载。</li>
<li>如果Expire头没过期，直接复用。</li>
<li>在缓存中没找到，发送请求，从服务上下载。</li>
</ol>
<p>其中第3点，IE的处理方式比其它浏览器严格，其它浏览器在刚才的测试页面中，不会重新下载。</p>
<p>另外，前面已经总结过，当切换到classA，开始下载imgA后，当classA又没用了时，IE会中断imgA的下载，而其它浏览器则会一直下载完。从逻辑上讲，IE的处理方式很严谨。但实际体验上，IE的处理方法很恼火。好与坏，有时真难评说。</p>
<h3>后记</h3>
<p>上面的结论，都仅仅是“定律”，建立在黑盒测试的基础上。可能会有不少错误之处，如果发现了，还望各位能及时反馈给我。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2009/05/img-http-request2/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
