<?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; image</title>
	<atom:link href="http://lifesinger.org/blog/tag/image/feed/" rel="self" type="application/rss+xml" />
	<link>http://lifesinger.org/blog</link>
	<description>关注用户体验、前端开发，记录生活点滴、岁月足迹。</description>
	<lastBuildDate>Wed, 28 Jul 2010 00:40:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Image Grabber Booklet</title>
		<link>http://lifesinger.org/blog/2009/11/image-grabber-booklet/</link>
		<comments>http://lifesinger.org/blog/2009/11/image-grabber-booklet/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 05:54:09 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[开发]]></category>
		<category><![CDATA[booklet]]></category>
		<category><![CDATA[image]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2239</guid>
		<description><![CDATA[代码： var o = "&#60;ol&#62;", bd = document.body; bd.innerHTML.replace( /(&#60;img[^&#62;]*)(src *= *("[^"]*"&#124;'[^']*'&#124;[^ &#62;]*))/ig, function(m, t, c, src) { t = src; c = src.charAt(0); if (c == '"' &#124;&#124; c == "'") t = t.slice(1, -1); o += "&#60;li&#62;" + t + " &#60;img src=" + src + " /&#62;&#60;/li&#62;"; }); bd.innerHTML = o + [...]]]></description>
			<content:encoded><![CDATA[<p>代码：</p>
<pre>
var o = "&lt;ol&gt;", bd = document.body;
bd.innerHTML.replace(
        /(&lt;img[^&gt;]*)(src *= *("[^"]*"|'[^']*'|[^ &gt;]*))/ig,
        function(m, t, c, src) {
            t = src; c = src.charAt(0);
            if (c == '"' || c == "'") t = t.slice(1, -1);
            o += "&lt;li&gt;" + t + " &lt;img src=" + src + " /&gt;&lt;/li&gt;";
        });
bd.innerHTML = o + "&lt;/ol&gt;";
</pre>
<p>Booklet 添加页面：<a href="http://lifesinger.googlecode.com/svn/trunk/lab/2009/img-src-regexp-test.html">img-src-regexp-test.html</a>（WordPress 的过滤好讨厌，只好放在独立页面里）</p>
<p>针对该功能，更简单明了的思路是用 getElementsByTagName(&#8220;img&#8221;) 来实现，但性能不如正则。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2009/11/image-grabber-booklet/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<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>
		<item>
		<title>图片的HTTP请求</title>
		<link>http://lifesinger.org/blog/2009/05/img-http-request/</link>
		<comments>http://lifesinger.org/blog/2009/05/img-http-request/#comments</comments>
		<pubDate>Tue, 12 May 2009 14:53:22 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[开发]]></category>
		<category><![CDATA[http request]]></category>
		<category><![CDATA[image]]></category>
		<category><![CDATA[prefetch]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=1661</guid>
		<description><![CDATA[请在主流浏览器中打开测试页面，在Fiddler里查看http请求。 1. 隐藏图片 &#60;img src="1.jpg" style="display: none" /&#62; 测试：test_1.html 结论：只有Opera不产生请求。 注意：用visibility: hidden隐藏图片时，在Opera下也会产生请求。 2. 重复图片 &#60;img src="1.jpg" /&#62; &#60;img src="1.jpg" /&#62; 测试：test_2.html 结论：所有浏览器都只产生一次请求。 3. 重复背景 &#60;style type="text/css"&#62; .test1 { background: url(1.jpg) } .test2 { background: url(1.jpg) } &#60;/style&#62; &#60;div class="test1"&#62;test1&#60;/div&#62; &#60;div class="test2"&#62;test2&#60;/div&#62; 测试：test_3.html 结论：所有浏览器都只产生一次请求。 4. 不存在的元素的背景 &#60;style type="text/css"&#62; .test1 { background: url(1.jpg) } .test2 { background: [...]]]></description>
			<content:encoded><![CDATA[<p>请在主流浏览器中打开测试页面，在Fiddler里查看http请求。</p>
<h3>1. 隐藏图片</h3>
<pre>
&lt;img src="1.jpg" style="display: none" /&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_1.html">test_1.html</a><br />
结论：只有Opera不产生请求。<br />
注意：用<code>visibility: hidden</code>隐藏图片时，在Opera下也会产生请求。</p>
<h3>2. 重复图片</h3>
<pre>
&lt;img src="1.jpg" /&gt;
&lt;img src="1.jpg" /&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_2.html">test_2.html</a><br />
结论：所有浏览器都只产生一次请求<span id="more-1661"></span>。</p>
<h3>3. 重复背景</h3>
<pre>
&lt;style type="text/css"&gt;
    .test1 { background: url(1.jpg) }
    .test2 { background: url(1.jpg) }
&lt;/style&gt;
&lt;div class="test1"&gt;test1&lt;/div&gt;
&lt;div class="test2"&gt;test2&lt;/div&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_3.html">test_3.html</a><br />
结论：所有浏览器都只产生一次请求。</p>
<h3>4. 不存在的元素的背景</h3>
<pre>
&lt;style type="text/css"&gt;
    .test1 { background: url(1.jpg) }
    .test2 { background: url(2.jpg) } /* 页面中没有class为test2的元素 */
&lt;/style&gt;
&lt;div class="test1"&gt;test1&lt;/div&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_4.html">test_4.html</a><br />
结论：背景仅在应用的元素在页面中存在时，才会产生请求。这对CSS框架来说，很有意义。</p>
<h3>5. 隐藏元素的背景</h3>
<pre>
&lt;style type="text/css"&gt;
    .test1 { background: url(1.jpg); display: none; }
    .test2 { background: url(2.jpg); visibility: hidden; }
&lt;/style&gt;
&lt;div class="test1"&gt;test1&lt;/div&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_5.html">test_5.html</a><br />
结论：Opera和Firefox对于用<code>display: none</code>隐藏的元素背景，不会产生HTTP请求。仅当这些元素非<code>display: none</code>时，才会请求背景图片。</p>
<h3>6. 多重背景</h3>
<pre>
&lt;style type="text/css"&gt;
    .test1 { background: url(1.jpg); }
    .test1 { background: url(2.jpg); }
&lt;/style&gt;
&lt;div class="test1"&gt;test1&lt;/div&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_6.html">test_6.html</a><br />
结论：除了基于webkit渲染引擎的Safari和Chrome，其它浏览器只会请求一张背景图。<br />
注意：webkit引擎浏览器对背景图都请求，是因为支持CSS3中的<a href="http://www.w3.org/TR/css3-background/#the-background-image">多背景图</a>。</p>
<h3>7. hover的背景加载</h3>
<pre>
&lt;style type="text/css"&gt;
    a.test1 { background: url(1.jpg); }
    a.test1:hover { background: url(2.jpg); }
&lt;/style&gt;
&lt;a href="#" class="test1"&gt;test1&lt;/a&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_7.html">test_7.html</a><br />
结论：触发hover时，才会请求hover状态下的背景。这会造成闪烁，因此经常放在同一张背景图里通过翻转来实现。<br />
<del>注意：在图片no-cache的情况下，IE每次hover状态改变时，都会产生一次新请求。很糟糕。</del><br />
<ins>2009-05-13晚补充：上面的解释有误，更详细的解释请参考<a href="http://lifesinger.org/blog/?p=1681">续篇</a>。翻转技巧指的是Sprite技术，例子：<a href="http://lifesinger.org/lab/2009/imghttp/test_7b.html">test_7b.html</a>, 在ie6下不会产生闪烁。</ins></p>
<h3>8. JS里innerHTML中的图片</h3>
<pre>
&lt;script type="text/javascript"&gt;
    var el = document.createElement('div');
    el.innerHTML = '&lt;img src="1.jpg" /&gt;';
    //document.body.appendChild(el);
&lt;/script&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_8.html">test_8.html</a><br />
结论：只有Opera不会马上请求图片。<br />
注意：当添加到DOM树上时，Opera才会发送请求。</p>
<h3>9. 图片预加载</h3>
<p>最常用的是JS方案：</p>
<pre>
&lt;script type="text/javascript"&gt;
    new Image().src = '1.jpg';
    new Image().src = '2.jpg';
&lt;/script&gt;
</pre>
<p>在无JS支持的环境下，可以采用隐藏元素来预加载：</p>
<pre>
&lt;img src="1.jpg" style="visibility: hidden; height: 0; width: 0" /&gt;
</pre>
<p>测试：<a href="http://lifesinger.org/lab/2009/imghttp/test_9.html">test_9.html</a></p>
<h3>终于到总结了</h3>
<ol>
<li>对于隐藏图片和隐藏元素的背景，Opera不会产生请求。</li>
<li>对于隐藏元素的背景，Firefox也不会产生请求。</li>
<li>对于尚未插入DOM树的img元素，Opera不会产生请求。</li>
<li>基于webkit引擎的Safari和Chrome，支持多背景图。</li>
<li>其它情景，所有主流浏览器保持一致。</li>
</ol>
<p>对图片请求的处理上，个人觉得Opera走在前列。</p>
<h3>番外</h3>
<p>1. 用Fiddler监控Opera时，如果是本地服务器，需要在Opera的代理服务器设置里，将本地服务器勾选上。</p>
<p>2. 查看HTTP请求数，还有一个万无一失的方法是，直接查看Apache的access.log文件。</p>
<p>3. 我的Firefox对于重复图片和重复背景，会产生重复请求。禁用了所有扩展，问题依旧。有知详情者，还望告知。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2009/05/img-http-request/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
	</channel>
</rss>
