<?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; 浏览器</title>
	<atom:link href="http://www.ilovejs.net/archives/tag/%e6%b5%8f%e8%a7%88%e5%99%a8/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ilovejs.net</link>
	<description>到了创造为主的阶段，不忘继续学习</description>
	<lastBuildDate>Thu, 15 Dec 2011 06:18:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>网站再优化</title>
		<link>http://www.ilovejs.net/archives/1156</link>
		<comments>http://www.ilovejs.net/archives/1156#comments</comments>
		<pubDate>Tue, 10 Aug 2010 16:44:56 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1156</guid>
		<description><![CDATA[今天闲来无事，就用Firebug查看首页的HTTP瀑布图，测试页面加载时间，发现在外联的css和js上时间开销还是挺大的，虽然css和js都进行了gzip压缩，但是解析延迟在某些时候还是比较厉害，不是css解析延迟就是js解析延迟，在读取缓存的时候，也有一定的读取的时间开销。 鉴于这种情况，那么干脆就将首页的css和js都嵌入到页面中吧，把css放到head、js放到body闭合标签之前，反正这两个文件在gzip压缩的条件下也总共才三四K而已，而子页面里还是使用外联css和js的方式。 经过这样倒弄，首页加载速度平均有100ms的提升，欣喜若狂。更好笑的是yslow、page speed测试都得了满分，哈哈…… 让首页嵌入css和js，而子页面外联的方式，主要是出于这样的一个目的：用户第一次浏览到首页的时候，页面可以尽快的呈现，而到了子页面，就加载css和js，这样的用户体验就有了一个类似于“稳步退化”的感觉，使得用户不会在起先的时候就有个不良感觉，而之后的访问，子页面就可以充分的利用缓存，因为子页面可能包含图片、flash等等，缓解HTTP的并发数。 还有，之前在浏览器下可能会有短暂的无样式与渲染样式之前切换的闪白，目前也得到了比较好的缓解。]]></description>
			<content:encoded><![CDATA[<p>
今天闲来无事，就用Firebug查看首页的HTTP瀑布图，测试页面加载时间，发现在外联的css和js上时间开销还是挺大的，虽然css和js都进行了gzip压缩，但是解析延迟在某些时候还是比较厉害，不是css解析延迟就是js解析延迟，在读取缓存的时候，也有一定的读取的时间开销。
</p>
<p>
鉴于这种情况，那么干脆就将首页的css和js都嵌入到页面中吧，把css放到head、js放到body闭合标签之前，反正这两个文件在gzip压缩的条件下也总共才三四K而已，而子页面里还是使用外联css和js的方式。
</p>
<p>
经过这样倒弄，首页加载速度平均有100ms的提升，欣喜若狂。更好笑的是yslow、page speed测试都得了满分，哈哈……
</p>
<p>
让首页嵌入css和js，而子页面外联的方式，主要是出于这样的一个目的：用户第一次浏览到首页的时候，页面可以尽快的呈现，而到了子页面，就加载css和js，这样的用户体验就有了一个类似于“稳步退化”的感觉，使得用户不会在起先的时候就有个不良感觉，而之后的访问，子页面就可以充分的利用缓存，因为子页面可能包含图片、flash等等，缓解HTTP的并发数。
</p>
<p>
还有，之前在浏览器下可能会有短暂的无样式与渲染样式之前切换的闪白，目前也得到了比较好的缓解。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1156/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>overflow:hidden带来的问题</title>
		<link>http://www.ilovejs.net/archives/1105</link>
		<comments>http://www.ilovejs.net/archives/1105#comments</comments>
		<pubDate>Thu, 05 Aug 2010 16:32:38 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[动画]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1105</guid>
		<description><![CDATA[即时更新：由@drunber提供的解决办法：设置父元素的padding或者border、float、position:absolute也可以解决问题，经测试验证通过。但是有一点需要说明的是：上下padding和border是必须要有数值的，设置为0无效。 但是对于动画来说，overflow:hidden是必须要设置的，否则里面的文本不会被遮盖。 &#8212;&#8212;&#8212;===========&#8212;&#8211; 即时更新分界线 &#8212;&#8212;===========&#8212;&#8212;&#8212;&#8211; 最近接到个需求，在搜索结果中添加下拉动画，高度和透明度都需要渐变。在测试过程中，遇到这样的一个问题：在一个div容器中包含了几个p标签，而且全在默认样式的情况，这样通过offsetHeight，clientWidth，scrollHeight等等获得div的高度，之后动态设置div的overflow样式属性为hidden，这样上面所获得的高度不准确了，《点击测试吧》，这样的后果就是动画被和谐了。 从这里的overflow:hidden对div的高度的差异可以看出：容器包含内容的解析原理。正常默认情况下，比如div包含一个p标签，这样div的宽高是会忽略p标签默认的margin值；但是一旦给div设置了overflow:hidden之后，div的实际宽高就需要加上p的margin值了。不过值得庆幸的是，在给div设置了overflow:hidden之后，通过offsetHeight等来获取div的宽高，是准确的。 从上面的分析中对于开头遇到的问题，就可以有三种方法来解决了：第一、在动态设置overflow:hidden之后来获取容器的高度，《点点测试吧》；第二、将p标签的margin清0处理，《再点点呗》；第三、干脆就不要使用p标签，改用没有默认margin的div吧，很勉强的方法，《最后点击测试下》。 Tip: 经过测试发现，设置overflow属性为hidden、auto都存在上面所说的情况。]]></description>
			<content:encoded><![CDATA[<p>
<em>即时更新：</em>由<em>@drunber</em>提供的解决办法：设置父元素的padding或者border、float、position:absolute也可以解决问题，经测试验证通过。但是有一点需要说明的是：上下padding和border是必须要有数值的，设置为0无效。
</p>
<p>
但是对于动画来说，overflow:hidden是必须要设置的，否则里面的文本不会被遮盖。
</p>
<p>
&#8212;&#8212;&#8212;===========&#8212;&#8211; 即时更新分界线 &#8212;&#8212;===========&#8212;&#8212;&#8212;&#8211;
</p>
<p>
最近接到个需求，在搜索结果中添加下拉动画，高度和透明度都需要渐变。在测试过程中，遇到这样的一个问题：在一个div容器中包含了几个p标签，而且全在默认样式的情况，这样通过offsetHeight，clientWidth，scrollHeight等等获得div的高度，之后动态设置div的overflow样式属性为hidden，这样上面所获得的高度不准确了，《<a  href="/lab/donghua/donghua.html">点击测试吧</a>》，这样的后果就是动画被和谐了。
</p>
<p>
从这里的overflow:hidden对div的高度的差异可以看出：容器包含内容的解析原理。正常默认情况下，比如div包含一个p标签，这样div的宽高是会忽略p标签默认的margin值；但是一旦给div设置了overflow:hidden之后，div的实际宽高就需要加上p的margin值了。不过值得庆幸的是，在给div设置了overflow:hidden之后，通过offsetHeight等来获取div的宽高，是准确的。
</p>
<p>
从上面的分析中对于开头遇到的问题，就可以有三种方法来解决了：第一、在动态设置overflow:hidden之后来获取容器的高度，《<a  href="/lab/donghua/donghua2.html">点点测试吧</a>》；第二、将p标签的margin清0处理，《<a  href="/lab/donghua/donghua3.html">再点点呗</a>》；第三、干脆就不要使用p标签，改用没有默认margin的div吧，很勉强的方法，《<a  href="/lab/donghua/donghua4.html">最后点击测试下</a>》。
</p>
<p>
<strong>Tip:</strong> 经过测试发现，设置overflow属性为hidden、auto都存在上面所说的情况。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1105/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CSS2.1的容错机制</title>
		<link>http://www.ilovejs.net/archives/1032</link>
		<comments>http://www.ilovejs.net/archives/1032#comments</comments>
		<pubDate>Wed, 07 Jul 2010 09:43:52 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[selector]]></category>
		<category><![CDATA[样式]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1032</guid>
		<description><![CDATA[CSS2.1是当前普遍使用着的CSS版本，平时如果循规蹈矩的编写CSS，或许不会发现问题，可问题就是：如果想要保存的时候，不小心按Ctrl+s的时候多留了一个s在CSS文件里，问题就开始来鸟；或者是不小心在规则的大括号外边多写了一个分号……出错的事情是千奇百怪的，对于新手来说频率可能会高些。出现这样的问题的时候、调试起来你可能会感觉很莫名其妙，这就需要了解一下CSS2.1版本的容错机制了。 CSS2.1的容错方式总的来说就是：对于出现一些无效的属性、属性值、@-keywords等等，它就会忽视这些样式声明或者整个规则声明。对于无效的属性、属性名会忽视该样式声明，对于@-keywords中keywords无效时，会将整个@-keywords包含的样式声明都忽略掉。 既然CSS2.1有这个容错机制，那么还有其他一些平时比较容易忽略的错误导致的样式失效的问题，下面举例出一些实例，看完下面的实例，基本可以了解CSS解析器解析CSS代码的一些原理了。 不要在CSS每个规则之间插入除空格之外的无效字符或者插入不合CSS语法的注释，否则该无效字符之后的第一个规则无效，例如： body{color:green;}. /*这里不小心多了个点号就杯具了*/ p.ten{color:red; background-color:green;} /*这个规则是无效的*/ p.one{color:red;} /*这个有效*/ 有一种情况比较特殊，当无效字符等使用大括号“{}”包含的时候，它下面的规则正常应用了，因为浏览器CSS解析器将它当作一条规则来处理。比如： body{color:green;} {.} p.ten{color:red; background-color:green;} /*它可以work啦*/ 跟上面对应的就是在样式中出现无效字符或者插入不合CSS语法的注释，则当前无效字符之后的第一条样式无效，例如： p.one{border-style:solid; . &#8230; <a href="http://www.ilovejs.net/archives/1032" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
CSS2.1是当前普遍使用着的CSS版本，平时如果循规蹈矩的编写CSS，或许不会发现问题，可问题就是：如果想要保存的时候，不小心按Ctrl+s的时候多留了一个s在CSS文件里，问题就开始来鸟；或者是不小心在规则的大括号外边多写了一个分号……出错的事情是千奇百怪的，对于新手来说频率可能会高些。出现这样的问题的时候、调试起来你可能会感觉很莫名其妙，这就需要了解一下CSS2.1版本的容错机制了。
</p>
<p>
CSS2.1的容错方式总的来说就是：对于出现一些无效的属性、属性值、@-keywords等等，它就会忽视这些样式声明或者整个规则声明。对于无效的属性、属性名会忽视该样式声明，对于@-keywords中keywords无效时，会将整个@-keywords包含的样式声明都忽略掉。
</p>
<p>
既然CSS2.1有这个容错机制，那么还有其他一些平时比较容易忽略的错误导致的样式失效的问题，下面举例出一些实例，看完下面的实例，基本可以了解CSS解析器解析CSS代码的一些原理了。
</p>
<ol>
<li>不要在CSS每个规则之间插入除空格之外的无效字符或者插入不合CSS语法的注释，否则该无效字符之后的第一个规则无效，例如：
<pre class="wp-code-highlight prettyprint">
body{color:green;}.  /*这里不小心多了个点号就杯具了*/
p.ten{color:red; background-color:green;} /*这个规则是无效的*/
p.one{color:red;} /*这个有效*/
</pre>
<p>有一种情况比较特殊，当无效字符等使用大括号“{}”包含的时候，它下面的规则正常应用了，因为浏览器CSS解析器将它当作一条规则来处理。比如：</p>
<pre class="wp-code-highlight prettyprint">
body{color:green;}
{.}
p.ten{color:red; background-color:green;} /*它可以work啦*/
</pre>
</li>
<li>跟上面对应的就是在样式中出现无效字符或者插入不合CSS语法的注释，则当前无效字符之后的第一条样式无效，例如：
<pre class="wp-code-highlight prettyprint">
p.one{border-style:solid; . color:#00c; font-weight:bold;}  /*color无效*/
</pre>
<p>但是有一种情况比较特殊，就是存在分号“;”的时候，前面带有无效字符也没影响。可能浏览器CSS解析器是将样式规则用分号进行拆分成数组，每个分号之前的样式不会影响下一个样式，比如：</p>
<pre class="wp-code-highlight prettyprint">
p.one{border-style:solid; . ; color:#00c; font-weight:bold;} /*color有效*/
</pre>
<p>因此从这里，有可以引申出一个问题：当编写每一个样式的时候最后没有加上分号，当前样式的下一个样式就会无效，因为浏览器把它解析成一整个属性:属性值对了（如果只有一个样式，或者是最后那个样式没有加上分号，则没什么影响。根据数组的split原理，建议是最后那个样式不加分号，这样就减少一个空的数组元素），比如：</p>
<pre class="wp-code-highlight prettyprint">
/*下面就杯具了*/
p.one{
  border-style:solid
  font-weight:bold
}
/*这还不错*/
p.one{
  border-style:solid;
  font-weight:bold
}
</pre>
</li>
<li>不要在颜色值(英文、十六进制等等)上加上双引号，否则该样式规则无效，例如：
<pre class="wp-code-highlight prettyprint">
body{color:&quot;red&quot;;background-color:&quot;green&quot;;}
</pre>
</li>
<li>给元素设置border的时候，如果没有设置border-color，则会使用字体的颜色来代替；如果没有设置border-width，则默认是medium。例如:
<pre class="wp-code-highlight prettyprint">
p.one{border-style:solid; color:#00c;}
</pre>
</li>
<li>在一些连写的CSS规则中，如果其中一个元素的规则声明出现错误，则整个规则无效，比如：
<pre class="wp-code-highlight prettyprint">
p.one,em @,strong{border-style:solid; color:#00c;} /*这里em @ 出错，造成整个规则失效*/
</pre>
</li>
<li>
如果在一个规则中样式进行了重复定义，如果其中一个样式的值无效（或者为空），那么不会覆盖有效的值的样式，因为浏览器会忽略掉无效值的样式声明，比如：</p>
<pre class="wp-code-highlight prettyprint">
p.ten{color:red; background-color:green;color:ss;} /*color还是red*/
</pre>
</li>
<li>规则声明不可以嵌套：p.ten{color:#00c;p.ten{color:#f00};background:#0c0}</li>
<li>在规则的特殊性方面，对元素声明样式时，将样式定义在它自身上和定义在它父元素上的优先级差别：将样式定义在子元素上，即使是使用标签类型的规则都比父元素使用ID、class、important等这样高优先级的都高，比如：span是p元素的子元素，p带有ID属性为ten
<pre class="wp-code-highlight prettyprint">
span{color:red;} /*文本的color样式还是red*/
body p#ten{color:green !important;}
</pre>
</li>
<li>对于无效的属性或者属性值，CSS解析器会直接忽略掉这些属性或者属性值，也就使得这条样式声明无效，比如：
<pre class="wp-code-highlight prettyprint">
img { float: left }       /* correct CSS 2.1 */
img { float: left here }  /* &quot;here&quot; is not a value of 'float' */
img { background: &quot;red&quot; } /* keywords cannot be quoted */
img { border-width: 3 }   /* a unit must be specified for length values */

/*解析过后，是：*/
img { float: left }
img { }
img { }
img { }
</pre>
</li>
<li>属性值中双引号和单引号要闭合，否则结果很悲剧，例如：
<pre class="wp-code-highlight prettyprint">
p {
   color: green;
   font-family: 'Courier New Times
   color: red;
   color: green;
}
解析过后，就成了：
p{
  color:green;
  color:green;
}
</pre>
</li>
</ol>
<p>
平时是我们太循规蹈矩的去编写CSS代码了，对于一些因为粗心造成的失误而导致样式失效的问题，浏览器又没有很好的提示CSS错误的功能，所以只能是通过肉眼看样式是否生效来测试CSS代码了。其实当你不遵循CSS语法来写的时候，会发现更多的CSS的解析失效问题，或许这就是CSS Hack被发现的源头吧……
</p>
<p>
详细CSS2.1容错机制可以浏览：<a  href="http://www.w3.org/TR/CSS21/syndata.html#parsing-errors">http://www.w3.org/TR/CSS21/syndata.html#parsing-errors</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1032/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>script的src和link的href属性值为空的陷阱</title>
		<link>http://www.ilovejs.net/archives/949</link>
		<comments>http://www.ilovejs.net/archives/949#comments</comments>
		<pubDate>Thu, 17 Jun 2010 21:48:20 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[(X)HTML]]></category>
		<category><![CDATA[DOCTYPE]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTML陷阱]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=949</guid>
		<description><![CDATA[2010-8-2 update:经过测试发现，但script的src和link的href属性值为#的时候，也会发生同样的事情：给服务器发送一个HTTP请求，并把当前页面作为返回值。浏览器的异同与下面的结论相同。通过js动态生成的script和link元素也一样。 &#8212;&#8212;&#8212;&#8212;-============&#8212;&#8212;&#8212;&#8212;-============&#8212;&#8212;&#8212;&#8212; 有些时候，我们在写HTML页面的过程中，通过script标签来外联外部的js文件，可是不小心给src属性赋值为空，当然有时候也会在link元素中带上了空属性值的href属性，我们想当然的认为这个没多大的影响，浏览器也会按照你认为的方式来解析它们。但是这个想当然估计错误了。先看几个测试页面：《HTML5 Doctype下href=”"》，《HTML5 Doctype下src=”"》，《XHTML1.0 Doctype下href=”"》。 使用firebug来查看DOM节点树的link和script节点，你就会发现怪异的事情发生了：link和script节点的内容居然是当前html页面的内容！！确实不可思议，就连容错机制最好的XHTML1.0的DTD声明也无济于事，这恐怕就是浏览器渲染页面的问题了。script节点src属性为空的时候就更恐怖了，会造成了语法错误。可更不可思议的是，出现这个问题的浏览器居然不是IE。经过多个浏览器的测试，IE和Opera都能很好的处理这个问题，可是Firefox、Chrome、Safari居然出现了。 对于这个初步总结为：当link标签的href属性为空、script标签的src属性为空的时候，浏览器渲染的时候会把当前页面的URL作为它们的属性值，从而把页面的内容加载进来作为它们的值。动态修改它们的href或者src属性值为空的时候，也将会出现这个问题：《动态修改href为空》。 因此，在我们平时写HTML页面，或者动态生成这两个标签的时候，尽量避免陷入了上面出现的陷阱，好好对待浏览器，编写符合规范的HTML标签语法和嵌套规则，多余的就别多此一举去倒弄，它回报给你的将是更少的开发时间和精力。 当某天你测试上面给出的测试样例并没有发现这个问题的时候，那就是浏览器修复了这个bug了。]]></description>
			<content:encoded><![CDATA[<p>
<strong>2010-8-2 update:</strong>经过测试发现，但script的src和link的href属性值为#的时候，也会发生同样的事情：给服务器发送一个HTTP请求，并把当前页面作为返回值。浏览器的异同与下面的结论相同。通过js动态生成的script和link元素也一样。
</p>
<p>
&#8212;&#8212;&#8212;&#8212;-============&#8212;&#8212;&#8212;&#8212;-============&#8212;&#8212;&#8212;&#8212;
</p>
<p>
有些时候，我们在写HTML页面的过程中，通过script标签来外联外部的js文件，可是不小心给src属性赋值为空，当然有时候也会在link元素中带上了空属性值的href属性，我们想当然的认为这个没多大的影响，浏览器也会按照你认为的方式来解析它们。但是这个想当然估计错误了。先看几个测试页面：《<a  href="/lab/evil/index1.html">HTML5 Doctype下href=”"</a>》，《<a  href="/lab/evil/index2.html">HTML5 Doctype下src=”"</a>》，《<a  href="/lab/evil/index3.html">XHTML1.0 Doctype下href=”"</a>》。
</p>
<p>
使用firebug来查看DOM节点树的link和script节点，你就会发现怪异的事情发生了：link和script节点的内容居然是当前html页面的内容！！确实不可思议，就连容错机制最好的XHTML1.0的DTD声明也无济于事，这恐怕就是浏览器渲染页面的问题了。script节点src属性为空的时候就更恐怖了，会造成了语法错误。<em>可更不可思议的是，出现这个问题的浏览器居然不是IE。经过多个浏览器的测试，IE和Opera都能很好的处理这个问题，可是Firefox、Chrome、Safari居然出现了</em>。
</p>
<p>
对于这个初步总结为：当link标签的href属性为空、script标签的src属性为空的时候，浏览器渲染的时候会把当前页面的URL作为它们的属性值，从而把页面的内容加载进来作为它们的值。动态修改它们的href或者src属性值为空的时候，也将会出现这个问题：《<a  href="/lab/evil/index4.html">动态修改href为空</a>》。
</p>
<p>
因此，在我们平时写HTML页面，或者动态生成这两个标签的时候，尽量避免陷入了上面出现的陷阱，好好对待浏览器，编写符合规范的HTML标签语法和嵌套规则，多余的就别多此一举去倒弄，它回报给你的将是更少的开发时间和精力。
</p>
<p>
当某天你测试上面给出的测试样例并没有发现这个问题的时候，那就是浏览器修复了这个bug了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/949/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>浏览器自动补全html、head、body引用，但是……</title>
		<link>http://www.ilovejs.net/archives/911</link>
		<comments>http://www.ilovejs.net/archives/911#comments</comments>
		<pubDate>Wed, 16 Jun 2010 10:26:37 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[document.body]]></category>
		<category><![CDATA[documentElement]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=911</guid>
		<description><![CDATA[2010-6-18 updates: surfing的时候发现了个非常不错的关于浏览器如何构建DOM树的工具：Live DOM Viewer。通过它可以非常直观的测试不同浏览器对解析HTML内容的差异。 2010-6-17 updates: 在跟番茄讨论这个问题的时候，他举例用CSS的样式来证明了body元素也会自动渲染的事实，这点本人没有想到，也没有经过测试就说了下面的文章（内容已经修改过了），惭愧……但是还存在这样的一个问题：就如下面的出现的情况，如果页面没有声明body标签的时候，为什么CSS可以渲染body的样式，而javascrpt无法直接调用document.body的引用？《测试用例》 经过一番测试和狂搜，大概明白了其中的原因，这需要了解javascrpt解析引擎和CSS渲染引擎是在什么时候介入页面起作用了。在浏览器解析HTML并生成DOM树的时候，是按从上至下的顺序解析的，浏览器最先会生成DOM树的根节点（HTMLDocument）和HTMLHEADElement（不知可否这样说），不管页面有没有声明html和head标签都会自动最先生成。之后再往下解析HTML标签，如果在遇到body标签（或者布局性标签）之前先遇到script标签的时候，就会在DOM树中生成该节点，但是这时这个script节点是head元素的子元素，而且这时候javascrpt解析引擎就会执行其中的代码（如果此时页面还没有解析到body的时候，或者还没有解析到如下面所说的布局性的标签的时候，DOM树中还不存在body节点，调用document.body就会出错），如果在body（或者其他布局性标签）之前，解析到link或者style标签，也会生成相应的节点，也是head的子节点，但是CSS渲染引擎并不会立即渲染页面的样式，它会在DOM树解析完成的时候才开始渲染页面，这就是上面的问题中所说的情况：CSS可以渲染body，而JS无法调用body的引用。《测试用例》，用firebug查看该实例生成的HTML结构。 所以，应该记住一点：如果在页面中使用script标签外联的js文件或者是行内脚本，当浏览器解析HTML内容的过程中遇到script标签的话，就会立即加载并且执行script的代码，之后才会继续解析后续的HTML的内容，除非是通过异步、动态加载js文件或者给script标签加上了defer、async属性。 但是如果在script或者link、style标签之前，有布局性的标签的时候，这就有两种情况了：没有文本内容的布局性标签和有文本内容的布局性标签。 当没有文本内容的时候。Chrome、Safari、Opera会将布局性标签下面的link、style、script等标签也渲染到body元素里（自动补全了该元素），这样通过script获取document.body的引用就没问题了。可是Firefox、IE会将link、style、script等标签都渲染到head元素里，先于body元素先在DOM树中生成，这样在js代码里直接获取document.body的引用就会出错。《测试用例》 当有文本内容的时候。各个浏览器都显示一致了。都会把link、style、script都渲染到body里，这样body元素就先于link、style、script标签等先在DOM树中生成，获取body的引用就没问题了。《测试用例》 ============================================================================ 正如题目中所说，一个正常的包含html、head、body的标签是不会出现这个问题的，页面都有声明了，浏览器它就省事多了。但是当页面没有html、head、body标签的时候，浏览器就有点发狂了，它惩罚偷懒的人的时候到咯。 在开始叙述之前，先来测试几个在不同的条件下的样例（这个测试主要是针对下面将要叙述的关于动态加载js来说的），下面将会提到一个暂时不知道怎么表达的词，就是我说的“布局性的标签”，它主要是指p、span、div等这些具有布局性质的元素，因此script、link、style等就不是了。 当页面无html、head、body标签，而且也没有其他的布局性的标签，只有一个script：《测试用例》。document.body出错了 当页面无html、head、body标签，有布局性的标签，而且带有文本内容（比如：&#60;p&#62;hello&#60;/p&#62;，嵌套的空标签也不行)，当这些标签在当前script标签前面的时候：《测试用例》。可以获得document.body的引用，它变好了。但是如果前面不是布局性的元素，或者是嵌套没有文本内容的布局性元素，《前面是link元素》，《嵌套空布局性元素》，在空布局性标签的情况下，IE、Firefox都挂了，chrome，safari，opera正常。前面是link元素的话全挂鸟。 当页面无html、head、body标签，有布局性的标签，而且不管有没有内容，当这些标签在当前script标签后面的时候：《测试用例》。document.body出错，它纠结了。 跟上面相同的条件，document.documentElement和document.getElementsByTagName(“head”)都可以获得引用：《documentElement》，《document.getElementsByTagName(“head”)》 &#8230; <a href="http://www.ilovejs.net/archives/911" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p><strong>2010-6-18 updates:</strong></p>
<p>
surfing的时候发现了个非常不错的关于浏览器如何构建DOM树的工具：<a  href="http://software.hixie.ch/utilities/js/live-dom-viewer/"><strong>Live DOM Viewer</strong></a>。通过它可以非常直观的测试不同浏览器对解析HTML内容的差异。
</p>
<p><strong>2010-6-17 updates:</strong></p>
<p>
在跟番茄讨论这个问题的时候，他举例用CSS的样式来证明了body元素也会自动渲染的事实，这点本人没有想到，也没有经过测试就说了下面的文章（内容已经修改过了），惭愧……但是还存在这样的一个问题：就如下面的出现的情况，如果页面没有声明body标签的时候，为什么CSS可以渲染body的样式，而javascrpt无法直接调用document.body的引用？《<a  href="/lab/load/js/">测试用例</a>》
</p>
<p>
经过一番测试和狂搜，大概明白了其中的原因，这需要了解javascrpt解析引擎和CSS渲染引擎是在什么时候介入页面起作用了。在浏览器解析HTML并生成DOM树的时候，是按从上至下的顺序解析的，浏览器最先会生成DOM树的根节点（HTMLDocument）和HTMLHEADElement（不知可否这样说），不管页面有没有声明html和head标签都会自动最先生成。之后再往下解析HTML标签，如果在遇到body标签（或者布局性标签）之前先遇到script标签的时候，就会在DOM树中生成该节点，但是这时这个script节点是head元素的子元素，而且这时候javascrpt解析引擎就会执行其中的代码（如果此时页面还没有解析到body的时候，或者还没有解析到如下面所说的布局性的标签的时候，DOM树中还不存在body节点，调用document.body就会出错），如果在body（或者其他布局性标签）之前，解析到link或者style标签，也会生成相应的节点，也是head的子节点，但是CSS渲染引擎并不会立即渲染页面的样式，它会在DOM树解析完成的时候才开始渲染页面，这就是上面的问题中所说的情况：CSS可以渲染body，而JS无法调用body的引用。《<a  href="/lab/load/js/index2.html">测试用例</a>》，用firebug查看该实例生成的HTML结构。
</p>
<p>
所以，应该记住一点：<strong>如果在页面中使用script标签外联的js文件或者是行内脚本，当浏览器解析HTML内容的过程中遇到script标签的话，就会立即加载并且执行script的代码，之后才会继续解析后续的HTML的内容，除非是通过异步、动态加载js文件或者给script标签加上了defer、async属性。</strong>
</p>
<p>
但是如果在script或者link、style标签之前，有布局性的标签的时候，这就有两种情况了：没有文本内容的布局性标签和有文本内容的布局性标签。
</p>
<ol>
<li>当没有文本内容的时候。Chrome、Safari、Opera会将布局性标签下面的link、style、script等标签也渲染到body元素里（自动补全了该元素），这样通过script获取document.body的引用就没问题了。可是Firefox、IE会将link、style、script等标签都渲染到head元素里，先于body元素先在DOM树中生成，这样在js代码里直接获取document.body的引用就会出错。《<a  href="/lab/load/js/index3.html">测试用例</a>》</li>
<li>当有文本内容的时候。各个浏览器都显示一致了。都会把link、style、script都渲染到body里，这样body元素就先于link、style、script标签等先在DOM树中生成，获取body的引用就没问题了。《<a  href="/lab/load/js/index4.html">测试用例</a>》</li>
</ol>
<p>============================================================================</p>
<p>
正如题目中所说，一个正常的包含html、head、body的标签是不会出现这个问题的，页面都有声明了，浏览器它就省事多了。但是当页面没有html、head、body标签的时候，浏览器就有点发狂了，它惩罚偷懒的人的时候到咯。
</p>
<p>在开始叙述之前，先来测试几个在不同的条件下的样例（这个测试主要是针对下面将要叙述的关于动态加载js来说的），下面将会提到一个暂时不知道怎么表达的词，就是我说的“布局性的标签”，它主要是指p、span、div等这些具有布局性质的元素，因此script、link、style等就不是了。</p>
<ol>
<li>当页面无html、head、body标签，而且也没有其他的布局性的标签，只有一个script：《<a  href="http://www.ilovejs.net/lab/load/">测试用例</a>》。document.body出错了</li>
<li>当页面无html、head、body标签，有布局性的标签，而且带有文本内容（比如：&lt;p&gt;hello&lt;/p&gt;，嵌套的空标签也不行)，当这些标签在当前script标签前面的时候：《<a  href="http://www.ilovejs.net/lab/load/index3.html">测试用例</a>》。可以获得document.body的引用，它变好了。但是如果前面不是布局性的元素，或者是嵌套没有文本内容的布局性元素，《<a  href="http://www.ilovejs.net/lab/load/index9.html">前面是link元素</a>》，《<a  href="http://www.ilovejs.net/lab/load/index2.html">嵌套空布局性元素</a>》，在空布局性标签的情况下，IE、Firefox都挂了，chrome，safari，opera正常。前面是link元素的话全挂鸟。</li>
<li>当页面无html、head、body标签，有布局性的标签，而且不管有没有内容，当这些标签在当前script标签后面的时候：《<a  href="http://www.ilovejs.net/lab/load/index4.html">测试用例</a>》。document.body出错，它纠结了。</li>
<li>跟上面相同的条件，document.documentElement和document.getElementsByTagName(“head”)都可以获得引用：《<a  href="http://www.ilovejs.net/lab/load/index7.html">documentElement</a>》，《<a  href="http://www.ilovejs.net/lab/load/index6.html">document.getElementsByTagName(“head”)</a>》</li>
</ol>
<p>
通过上面各种条件的测试，可以得出这样的结论：当页面中没有声明html、head、body标签的时候，也没有其他的布局性的标签（除了script、style、link等），各个浏览器在DOM文档树中会自动补全html、head、body的引用，ie还会自动补全title标签，后续的js代码可以获得html、head元素的引用，但是得不到body的引用。如果包含了布局性的元素，而且这些元素包含文本内容（从兼容性出发），后续的js代码可以获得document.body的引用。但是如果布局性的元素在js代码之后，则在前面的js代码中无法获得body标签的引用。
</p>
<p>
根据浏览器的这一个特性，对上面所说的条件可以再缩小化的：当没有声明body标签的时候，也都会出现上面所说的无法直接得到document.body引用的问题。《<a  href="http://www.ilovejs.net/lab/load/index10.html">测试用例</a>》
</p>
<p>
因此，不管页面中有没有声明html、head标签，各个浏览器（连IE6都fuck能这么做了）都会在DOM文档树中自动补全html、head、body元素的引用，而操作body则需要小心点了，防止出现上面测试用例中提到的无法获得document.body引用的失误。
</p>
<p>
从这点出发，联想到<a  href="http://www.stevesouders.com">Steve Souders</a>在它的一篇博文中《<a  href="http://www.stevesouders.com/blog/2010/05/11/appendchild-vs-insertbefore/">appendChild vs insertBefore</a>》提到的在动态插入js文件的时候，如果页面中缺少head、body的标签的情况，是该用appendChild还是insertBefore的比较。根据上面的测试，页面不管有没有head声明，都会自动补全head元素的引用，所以使用下面的方式都是能够适用于大部分场合的：
</p>
<p>[javascript]<br />
var script = document.createElement(&quot;script&quot;);<br />
script.setAttribute(&quot;src&quot;,&quot;/wp-content/j/combine_js.js.php&quot;);<br />
document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script);<br />
[/javascript]<br />
不过jQuery的实现方式是把document.documentElement也考虑在内了，并且使用了insertBefore的方式：《<a  href="http://www.ilovejs.net/lab/load/index8.html">测试用例</a>》<br />
[javascript]<br />
head = document.getElementsByTagName (&quot;head&quot;)[0] ||<br />
    document.documentElement;<br />
// Use insertBefore instead of appendChild to circumvent an IE6 bug.<br />
// This arises when a base node is used (#2709 and #4378).<br />
head.insertBefore(script, head.firstChild);<br />
[/javascript]</p>
<p>
jQuery能用head元素在它的firstChild之前插入script标签的技巧是借助于在上面出现的情况中，IE下会自动补全head元素，并且还会自动补全title元素，而FF等浏览器下则是利用了空节点作为firstChild。而对于它所说的IE6的bug，我估摸不透。但是浏览器会自动补全head元素，所以再使用document.documentElement，也就觉得有点多此一举了。
</p>
<p>
但最重要的是，人不要那么懒啦，声明一个完整的HTML页面吧，这样浏览器会亲死你~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/911/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>浏览器解析样式表的异同</title>
		<link>http://www.ilovejs.net/archives/861</link>
		<comments>http://www.ilovejs.net/archives/861#comments</comments>
		<pubDate>Thu, 10 Jun 2010 08:21:18 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[CSS Minify]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[样式表]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=861</guid>
		<description><![CDATA[2010-6-28 updates 之前的测试都在页面中直接通过link元素外联css文件，但是动态插入的情况呢？（非常感谢Emu的提醒） 因此，又测试了使用DOM Element的方式来动态插入link元素，并外联css文件，可是问题依旧，《测试示例》。IE、Chrome、Safari照常需要等到全部的样式表都加载下来才开始呈现页面样式；FF、Opera是加载完一个样式表就渲染页面，而不需要等到全部的样式表都加载下来。 之后，测试使用一个定时器(setTimeout)的方式来异步执行动态加载css文件，《测试页面》，这下子就有点意思了：IE出现了无样式内容闪烁，仍然需要等全部的样式表都加载下来之后才呈现页面；Chrome、Safari跟FF、Opera一样了，加载完一个样式表就渲染页面，不需要等到全部的样式表都加载下来。 不过定时器的方式虽然解决了Chrome、Safari的问题，但是使得IE可能会出现无样式内容闪烁，所以也并不是很完美的方案，就看网站的用户群偏向哪些浏览器多一些了，并对这些浏览器做这方面的优化。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 完美的分界线 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 一直存在一个疑问：IE同其他主流浏览器的兼容性差异都涉及到布局、HTML、Javascript、CSS规则等方面，但是对于解析样式表来渲染整个页面呢，是否也存在异同？当看到Steve Souders的博文《Frontend SPOF》，迷惑揭开了，文中对各种浏览器解析样式表的机制做了如下描述： Browsers are split on how they handle &#8230; <a href="http://www.ilovejs.net/archives/861" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p><em><strong>2010-6-28 updates</strong></em></p>
<p>
之前的测试都在页面中直接通过link元素外联css文件，但是动态插入的情况呢？（非常感谢<a  href="http://blog.csdn.net/emu">Emu</a>的提醒）
</p>
<p>
因此，又测试了使用DOM Element的方式来动态插入link元素，并外联css文件，可是问题依旧，《<a  href="/lab/loadcss/">测试示例</a>》。IE、Chrome、Safari照常需要等到全部的样式表都加载下来才开始呈现页面样式；FF、Opera是加载完一个样式表就渲染页面，而不需要等到全部的样式表都加载下来。
</p>
<p>
之后，测试使用一个定时器(setTimeout)的方式来异步执行动态加载css文件，《<a  href="/lab/loadcss/index2.html">测试页面</a>》，这下子就有点意思了：IE出现了无样式内容闪烁，仍然需要等全部的样式表都加载下来之后才呈现页面；Chrome、Safari跟FF、Opera一样了，加载完一个样式表就渲染页面，不需要等到全部的样式表都加载下来。
</p>
<p>
不过定时器的方式虽然解决了Chrome、Safari的问题，但是使得IE可能会出现无样式内容闪烁，所以也并不是很完美的方案，就看网站的用户群偏向哪些浏览器多一些了，并对这些浏览器做这方面的优化。
</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 完美的分界线 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>
一直存在一个疑问：IE同其他主流浏览器的兼容性差异都涉及到布局、HTML、Javascript、CSS规则等方面，但是对于解析样式表来渲染整个页面呢，是否也存在异同？当看到<a  href="http://www.stevesouders.com">Steve Souders</a>的博文《<a  href="http://www.stevesouders.com/blog/2010/06/01/frontend-spof/">Frontend SPOF</a>》，迷惑揭开了，文中对各种浏览器解析样式表的机制做了如下描述：
</p>
<blockquote><p>
Browsers are split on how they handle stylesheets. Firefox and Opera charge ahead and render the page, and then flash the user if elements have to be redrawn because their styling changed. Chrome, Internet Explorer, and Safari delay rendering the page until the stylesheets have arrived. (Generally they only delay rendering elements below the stylesheet, but in <a  href="http://stevesouders.com/hpws/css-bottom.php">some cases</a> IE will delay rendering everything in the page.) If rendering is blocked and the stylesheet takes a long time to download, or times out, the user is left staring at a blank page. There’s not a lot of advice on loading stylesheets without blocking page rendering, primarily because it would introduce the <a  href="http://www.bluerobot.com/web/css/fouc.asp/">flash of unstyled content</a>.
</p></blockquote>
<p>
上面说的很明白，对于样式表的加载和渲染的原理，不同的浏览器下有不同的行为，主要是分为Firefox、Opera和IE、Chrome、Safari两类。
</p>
<p>
Firefox、Opere在加载样式表的时候是边加载边渲染。这样既有利也有弊：利在使得页面可以尽快的开始渲染，而无须等待全部的样式表都加载下来之后再开始渲染，延迟了页面渲染；而弊端在于之前加载并渲染的样式在后面又重新定义或者修改了布局样式，那么将会造成一定程度上的闪烁，闪烁的程度主要看所影响的元素的范围和数目。
</p>
<p>而IE、Chrome、Safari则是在全部的样式表完全加载下来之后才开始渲染页面样式。这样做也同样是有利有弊：利在于可以避免Firefox、Opera中出现的闪烁的问题（虽然在IE下闪烁是经常的事情），可以确保样式会统一解析并渲染页面；而弊端在于页面全部样式表的加载延迟了页面渲染的时间，如果样式表加载的时间较长，或者加载错误，将会导致页面一直处于空白状态或者无样式状态，还有可能是“无样式内容的闪烁“的问题的出现。
</p>
<p>
为了证实上面的说法，进行了一个测试，这个测试的关键是延迟样式表的加载，但是不能延迟了HTML页面的加载和解析，并在页面中添加几个样式表做比较。为此，利用PHP的sleep函数在其中一个样式表中延迟3秒，并放到body的底部来加载，而另外一个样式表放到head里加载：《<a  href="http://www.ilovejs.net/lab/loadcss/test.css.php">浏览器解析样式表的测试</a>》。测试结果很明显：FF、Opera是首先解析了第一个样式表，等第二个延迟加载的样式表加载下来的时候，改变了第一个样式表的样式，出现了闪烁；IE、Chrome、Safari则是需要等到第二个样式表也加载下来的时候才开始渲染页面样式，导致了3秒的渲染延迟。
</p>
<p>
通过上面的测试证实，明白了在页面中Minify CSS、Put CSS at the head的实质理由和重要性：<strong>最小化页面渲染延迟时间</strong>。并总结出下面几点：
</p>
<ol>
<li>尽量避免将样式表放置到body中来加载，避免IE、Chrome、Safari延迟页面开始渲染的时间，也避免IE下的“空白闪烁”和“无样式内容的闪烁”等问题。</li>
<li>如果页面中有几个样式表，尽量合并为一个样式表文件，避免FF、Opera样式闪烁的问题。既然文件大小总量不变，那就尽量保持HTTP请求数的最小化吧。</li>
<li>在样式表Minify后，再Gzip压缩下，效果更佳，最小化各个浏览器对于加载并解析样式表的差异性而造成不同程度的用户体验的影响。</li>
<li>尽早的让样式表加载，最好是在加载并解析HTML之后就开始加载样式表。但是也要避免样式表后紧跟行内脚本，从而造成对后续资源的阻塞。</li>
<li>对于当前页面使用不到的样式表，就删除掉，避免整个站点的页面都使用同一个样式表，从而节省不必要的宽带和使得页面的渲染时间越早越好。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/861/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

