广义论及HTML5时,实际指的是包括HTML、CSS和JavaScript在内的一套技术组合。它希望能够减少浏览器对于需要插件的丰富性网络应用服务(plug-in-based rich internet application,RIA),如Adobe Flash、Microsoft Silverlight与Oracle JavaFX的需求,并且提供更多能有效增强网络应用的标准集。
目前HTML5已向开发人员提供了很多新的标签,如section,nav,article,header和footer等。这些标签语义化程度高,会被经常使用,但在IE6,IE7,IE8和Firefox 2等老式浏览器中却不能识别和正常使用。
一、HTML5标签在浏览器展示存在的问题
对于现阶段来说,使用HTML5标签可能遇到的最大问题就是如何在不支持新标签的浏览器中做恰当的处理。当我们在页面中使用HTML5元素时,可能会得到三种不同的结果。
结果1:标签被当作错误处理并被忽略。那么DOM构建的时候,就会当作这个标签不存在。
结果2:标签会被当作错误处理,并在DOM构建的时候依然会按照预期的代码进行创建,并且HTML标签会被构造成行内元素(也就是说虽然不能识别,但是代码里section标签依然会在dom中创建一个对应section节点,但是属于行内元素)。
结果3:标签被识别为HTML5标签,然后用DOM节点对其进行替换。DOM在构建的时候和预想的一致,并且合适的样式会应用到标签上(大部分情况下是块级元素)。
有一个具体的例子,大家思考一下下面的代码:
<div class="outer">
<section>
<h1>title</h1>
<p>text</p>
</section>
</div>
很多浏览器(比如Firefox 3.6和Safari4)解析的时候都会将div作为最外层的元素,然后div里面是一个识别不了的元素(section),它会在DOM中创建,并被作为一个行内元素存在。h1和p元素都是作为section元素的子节点。因为section在DOM中真实存在,所以也可以修改其样式。这种情况对应结果2。
IE9之前的版本会认为section标签是一个错误,并直接将其忽略,那么h1和p标签会被解析,然后成为div标签的子节点。</section>也会被认为是一个错误并直接跳过。在这些浏览器中实际有效的代码是这样的:
<div class="outer">
<h1>title</h1>
<p>text</p>
</div>
那么,旧版本的IE浏览器除了生成的DOM结构和其他浏览器不一样,其对不可识别标签的容错能力还是很棒的。因为section节点没有在DOM树中构建,所以也就不能给其增加样式。这种情况对应结果1。
当然,支持HTML5的浏览器比如IE9,Firefox4+,Safari5+会创建正确的DOM结构,然后这些标签会默认附带HTML5规范中定义的默认样式。
那么,我们所面临的最大问题就是同样的代码在不同的浏览器中形成了不同的DOM结构,并且含有不同的样式。
二、如何解决HTML5标签不兼容
或许会有很多人在质疑:为什么老式的浏览器不能识别这些标签?其实错不在浏览器,因为在那个时代根本不存在这种标签,所以不能正确识别出来,而这种不寻常的标签识别令DOM结构变得异常。对此,人们想出了很多在现阶段页面中使用HTML5元素的解决方案。每一个解决方案为了做到兼容都会遇到一些特定的问题。在此也在马海祥博客上跟大家分享一下:
1、实现标签被识别
马海祥曾做个一个测试(以IE8为例),是一个文章标题和蓝色字的文章内容,其中文章内容用了article标签。代码如下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>测试</title>
<style>
article{color:#06F}
</style>
</head>
<body>
<h1>文章标题</h1>
<article>
这是文章内容,应该是一段蓝色的文字。在老式浏览器中,如果不做hack将显示异常。
</article>
</body>
</html>
在IE8浏览器中,显示如下:
IE8不能识别article标签, 定义在标签上的CSS样式没有起作用。 在IE8中,<article>被解释成命名为<article />和</article />两个空的标签元素,与文章内容并列为兄弟节点,如下图所示:
既然因为不能识别标签而不能使用,那我们的解决办法就是让标签被识别出来。所幸,简单地通过document.createElement(tagName)即可以让浏览器识别标签和CSS引擎知道该标签的存在。假设我们上面的例子的<head>区域加上如下代码。
<script>
document.createElement('article')
</script>
IE8浏览器中的DOM解释就会变成下图所示:
自然,文字也显示成正常的蓝色。如下图所示:
2、JavaScript解决方案
JavaScript解决方案目的是解决在旧版本的IE中样式应用的问题。老版本的IE不会识别不明元素已经是一个耳熟能详的特性,而如果这些元素已经通过document.createElement()创建,那么浏览器就可以识别这些标签,并可以将其在DOM树中构建,然后允许开发者对其应用样式。
这个方法可以确保HTML5标签能在旧版本IE中对应创建DOM节点,然后可以对其应用样式。这个方法将HTML5块级元素设置成display:block,从而可以在各个浏览器中做到兼容。
今天测试以下把马海祥博客的网页改成了HTML5的,调试了一下,在FF和Opera中都显示正常了,到了IE6上却变得面目全非了。对此我还特意去找了一些使用JS代码支持HTML5标签元素的方法,在此也跟大家分享一下:
(1)、使用html5shiv
查看了一下,发现了html5shiv能解决这个问题,可以把HTML5的新元素转换成IE6认识的内容。只需要在你的head中调用这段代码就行:
<!--if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
当然你也可以直接把这个文件下载到自己的网站上。但这个文件必须在head标签中调用,因为IE必须在元素解析这前知道这些元素,才能启作用!但马海祥还要提醒你一下:还要在你的CSS文件中加上以下代码,不然有可能会出现些莫名其妙的问题。
header,nav,article,section,aside,footer{display:block}
另外excanvas.js是Google为IE6支持canvas元素写的脚本,以后马海祥会跟大家再细说这样的例子,感兴趣的朋友可以去试试。
(2)、使用Kill IE6
除此之外你还可以使用KILL IE6一族,前提是你的浏览器允许执行JS文件。方法很简单,在你的网站的</body>之前加上以下代码就可以了:
<!--if lte IE 6]>
<script src="http://letskillie6.googlecode.com/svn/trunk/letskillie6.zh_CN.pack.js"></script>
<![endif]-->
上面写的<!--if lte IE 6]>在正常的HTML中属于注释,不会被执行,但在IE中是一个判断语句,所以这些代码只有在IE中才会被识别并加载。
lte:就是Less than or equal to的简写,也就是小于或等于的意思。
lt :就是Less than的简写,也就是小于的意思。
gte:就是Greater than or equal to的简写,也就是大于或等于的意思。
gt :就是Greater than的简写,也就是大于的意思。
! : 就是不等于的意思,跟javascript里的不等于判断符相同
说实话,马海祥不喜欢这个利用JavaScript解决的方案,因为它破坏了我最主要的web应用开发原则:我们不应该使用JavaScript来控制布局。不仅仅是因为这个做法给那些禁用脚本的用户带来了糟糕的用户体验,更重要的是,如果我们希望我们的web应用代码是面向未来,并且维护性高的,那么必须将视图相关部分分离出来。这个方案对在跨浏览器中构建相同的DOM结构很有帮助,也可以确保你的JavaScript和CSS在各个地方运行结果相同,但是这个优势并不能改变我对这个方法的不认同。
3、Namespace hack
永远不要缺乏使用hack解决问题的能力,在IE中还有其他技术来让浏览器识别不明的标签。这个来自Elco Klingen日志的方法一开始引起了广泛的关注。该技术包含了一个XML形式的命名空间,并使用了含有namespace前缀的元素。例如:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html5="http://www.w3.org/html5/">
<body>
<html5:section>
<!-- content -->
</html5:section>
</body>
</html>
前缀html5是纯粹是用于这个例子而且也不是官方支持的,你甚至可以用"foo"作为前缀,结果还是一样。有了前缀之后,IE会识别新的元素,从而可以应用样式。在其他浏览器中一样有效,那么最后,你就成功地在各个浏览器中构建了一样的元素和一样的样式。
这个方法的缺陷很明显:你必须在HTML文档中使用XML格式的命名空间,同样,你也需要在css中这么做:
html5\:section {
display: block
}
马海祥点评:这并不是我期望Web开发者编写代码的方式。虽然这是一个非常杰出的解决方案,但是这让应用变得不自然。我不希望看到文件中充满了带命名空间的元素。
4、Bulletproof技术(防弹衣技术)
说实话,我是第一次接触到这个技术,建议在所有新的HTML5块级元素中增加一个内部的div元素,然后包含一个CSS class,用这个元素来替代HTML元素(类似在里面穿了一件防弹衣),例如:
<section>
<div class="section">
<!-- content -->
</div>
</section>
在应用样式的时候,Tantek推荐直接给div增加样式,而不是给新元素增加样式
推荐使用:
.section {
color: blue
}
而不是:
section {
color: blue
}
这个方案的原理是用简单的方式将原来的样式应用方式转移到一个代表了HTML5标签的元素上。由于我一般情况下不会将样式通过标签名的方式应用到元素上,所以马海祥也并完全支持这个建议。
马海祥觉得这个方案的缺陷是不同的浏览器构建了不同的DOM结构,那么你必须在编写JavaScript和CSS的时候格外小心。获取子节点或者父节点的时候,不同的浏览器返回的结果可能会不一样。特别是在下面的代码中:
<div class="outer">
<section>
<div class="section main">
<!-- content -->
</div></section>
</div>
5、反向的bulletproof技术
还有一些方法,比如尝试使用和Tanteck方案相反的技术,也就是把HTML5元素放在div元素内部,例如:
<div class="section">
<section>
<!-- content -->
</section>
<div>
这个方案唯一的不同是HTML5元素的位置,其他都一样。喜欢这个技术的支持者认为他的一致性很好(适用于所有的元素,包括<hgroup>)。但是DOM结构的不同让这个方案意义变得不大。他的主要优势是技术上的一致性。
6、关于X-UA-Compatible的使用
目前绝大多数网站都用以下代码来作为IE8的兼容方法。
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" >
虽然微软将IE向标准迈进了一大步,而事实上IE8还存在一系列渲染的奇怪现象是不争的事实。
在X-UA-Compatible中可用的方法有:
<meta http-equiv="X-UA-Compatible" content="IE=6" >
<meta http-equiv="X-UA-Compatible" content="IE=7" >
<meta http-equiv="X-UA-Compatible" content="IE=8" >
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
其中最后一行是永远以最新的IE版本模式来显示网页的。
另外加上
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" >
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" >
而使用,Emulate模式后则更重视。
所以目前来说还是以使用
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" >
为首选。
7、通过修改HTML部分来实现
我的主要目标是确保我只需要修改HTML部分。这就意味着不需要修改CSS和JavaScript。为什么会有这样的需求?需要修改的Web应用视图越多,你越有可能制造bug。将改变限制到一个视图也就限制了bug的出现,即使出现了bug,也可以减少你查找错误的范围。如果一个视图破相了,我可以知道这是因为我增加了一个section元素,而不是考虑是不是CSS文件修改来带的影响。
在研究了所有这些解决方案,并进行一些尝试和设计之后,我回到了Tantek的方案。这是唯一一个只需要修改HTML而不用动CSS和HTML的方案。现在,我在他的方案基础上做了一些改进,来达到我想要的结果。
首先,我不会给那些代表HTML5元素的class增加样式(所以我不会使用.section这样的选择器)。我保留了div元素,然后再增加一个带语义的class来应用样式,并作为进行JavaScript操作的钩子。例如,这样的代码:
<div class="content">
<!-- content -->
</div>
经过改进后:
<section>
<div class="section content">
<!-- content -->
</div>
</section>
这样的修改完成后,我依然使用.content作为样式和脚本的入口。这也意味着我不需要修改CSS和JavaScript。
然后,为了避免hgroup标签这样的情况,我选择不使用这个标签。我在我已有的所有页面中没有找到任何一个使用了这个标签的。由于hgroup标签只能包含标题元素,如果你确实想要使用这个标签,那么使用hrgoup来包含本身是非常安全的(假设它没有包含其他的块级元素)。
我在马海祥博客上花了很多时间来测试比较bulletproof和反向的bulletproof哪个更好一些。我做选择时最主要的决定因素就是反向的bulletproof需要我去增加CSS代码。在那些为HTML5标签创建了DOM节点但是没有应用默认样式的元素来说,div元素里包含了一个HTML5块级元素在很多情况下都会搅乱我的布局,因为创建的DOM节点是行内元素。我不得不明确增加CSS规则来让这个节点变成块级元素从而可以正常布局,这也就违反了我不修改CSS文件的初衷。
马海祥博客点评:
在我的研究中,我使用了多个页面,然后在这些页面上使用修改过后的bulletproof技术。我分别在简单和复杂的布局中,含有和不含有JavaScript交互进行测试。在每一个例子中,我只需要修改HTML就可以让页面表现正确(不修改JavaScript和CSS)。那么,子节点和父节点的问题怎么办?有趣的事情是我在测试中并没有遇到这样的问题。
理由很简单,因为我对代码苛刻的态度。我认真地做了第二遍检查:
(1)、标签名和ID不会用于应用样式(只是用class)。
(2)、尽量选择常用的CSS选择器并且尽量减少选择器的使用。
(3)、JavaScript代码不依赖于特定的DOM结构。
(4)、标签名不用于操作DOM。
我注意到另一个有趣的事情是我使用了HTML5元素作为容器。而这些新的元素仅仅是作为功能性模块的边界。你应该花费你的大部分时间为内部的元素编写样式和脚本而不是处理各个模块间的样式和脚本。由于马海祥博客的JavaScript和CSS标签都应用在容器的内部,所以一切都显得很顺利。我想这才是一个真正的代码质量高的网站。
这个很简单,我告诉你正解这里面用到的技术:ajax,div层的概念,javascript的第三方特效库
div层的概念:类似于一个容器,能够容纳图片等。用代码来解释就是:“<div>这里存放图片</div>”
略缩图和大图:图像可以用代码来控制显示的大小,所以你能够看到小图和大图
当你点击略缩图示,你最先看到一块白色区域,中间的地方有个加载等待图案,这里面用到了ajax技术,同时用到了div层的概念(稍候解释)。当ajax接收到了图片加载完毕的信息后,会告知浏览器,可以显示图片了。
第二步,图片显示在白色区域中。
为什么有些时候白色区域会变小?
因为这里又用到了第三方的js函数库,他的作用的过渡效果,即div层的移动。所以你会看到白色区域慢慢的向图片边缘靠拢。
问什么你点击不到其他地方?
用技术的角度来解释,就是在你第一次点击小图的时候,他已经自动创建的一个透明的div层在上面,所以你点不到他
这就类似于你在桌子上放一幅画,而在画的上面放上玻璃板,当你用笔去往上写东西的时候,当然不会写到画上面。
我说,大哥,你明白了吗?我解释的不容易啊,给分吧
********************************************
我是搞web开发的,如果用我们的专业术语来给你解释,你能明白吗?你有什么依据来证实你说的是对的?代码的编译原理,程序执行的先后顺序,我能够用我的经验判断出来。如果你想真正弄清楚这是怎么一回事,我希望你看看javascript和html基本语法知识(特别是div的用法,设置他的style的z-index属性和filter属性,然后就是js的基本语法和dom规范),然后再来提问。这样效果会好一些,前提是你愿意在这上面花费一些时间
*********************************************
页面确实有flash控件,但只有一个地方用到了,而图片显示的时候没有用到。共两个文件如下(webroot代表应用根目录)
名称:flash_ad_relay.swf
目录:webroot/comic/flasher/ads_data/
名称:imgad.swf
目录:webroot/comic/flasher/ads_data/
说明:通过观察ads.htm(目录在webroot/comic/flasher/)文件代码,能够判断,flash_ad_relay.swf应该是google提供的一个flash控件,其作用是控制广告程序的加载进度。而imgad.swf则是一个广告(ad)程序,当当网的那个,在页面最下面。
总体来说flash_ad_relay.swf用来控制imgad.swf文件加载的进度并且显示。
入口方法:tianchaoyu.html文件中<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
此行代码用来加载flash广告程序,这应该是遵循了google的命名规范和目录结构。
上面这个是我个人推测的,但只有这一个地方用到flash文件,图片显示完全没有用到。
**********************************************
lightbox.css文件
目录:http://www.songzg1.com/comic/flasher/css/lightbox.css
说明:#outerImageContainer{
position: relative
background-color: #fff
width: 250px
height: 250px
margin: 0 auto
}
上面为lightbox.css代码片断,width: 250pxheight: 250px控制了图片第一次点击的时候初始化大小为250像素*250像素 在17寸1024*768分辨率上。加载的过程中用到了loading.gif图片(http://www.songzg1.com/comic/flasher/images/loading.gif),你可能是因为这个原因把它理解成flash吧。这只是一张gif图而已。
当点击图片,图片数据传输完毕之后,能够获得图片的宽高属性,根据这些属性,那个div层(<div><img /></div>)会自动扩大或缩小,以适应新的图片。这就是你看到的过渡效果。
处理放大缩小过渡效果的文件是lightbox.js,而effects.js也有一些坐标变化的处理。
lightbox.js是一个简单实用的用来把图片覆盖在当前页面上的脚本. 它能被快速安装并且运作于所有流行的浏览器.。这个网站上用的是2.02版本,它是由Lokesh Dhakar人于20060331日创建的,可以通过http://www.huddletogether.com察看相关信息。
最后介绍使用方法,非常easy
**********************************************
先说一下其他两个js框架
prototype.js
它是一个非常优雅的javascript基础类库,对javascript做了大量的扩展,而且很好的支持Ajax,国外有多个基于此类库实现的效果库,也做得很棒。
像前面提到的lightbox.js和后面要说的effects.js是基于prototype.js实现的,他们通常结合使用。
scriptaculous.js和effects.js
这是个动画效果库。
scriptaculous 包含以下几个部分:
builder.js :提供了一种方便的建立html元素的方法
controls.js :包含自动提示和动态编辑两个控件
dragdrop.js : 提供元素拖放的功能
effects.js : 设计优良的ajax效果库,这篇文章要讲的就是这个
slider.js : 一个滑动条控件
effects.js中提供了两种类型的动画效果,一种称为核心效果(core effect),一种称为组合效果(combination effect)
**********************************************
结合使用
第一步
Lightbox v2.0 使用 Prototype 框架和 Scriptaculous 效果库. 你将需要外调这三个 Javascript 文件在你的 header.
代码:
<script type="text/javascript" src="js/prototype.js"></script>
<script type="text/javascript" src="js/scriptaculous.js?load=effects"></script>
<script type="text/javascript" src="js/lightbox.js"></script>
第二步
外调 Lightbox CSS 文件 (或添加 Lightbox 样式到你现行的样式表中).
<link rel="stylesheet" href="css/lightbox.css" type="text/css" media="screen" />
第三步
检查 CSS 并确定调用的 prev.gif 和 next.gif 文件在正确的位置. 同样要确定调用的 loading.gif 和 close.gif 文件及 lightbox.js 文件在正确的位置.
方式一:添加 rel="lightbox" 属性到任何一个链接标签去激活lightbox. 例如:
<a href="images/image-1.jpg" rel="lightbox" title="my caption">image #1</a>
方式二:如果你有一套你想分组的相关图片, 接着上一部并且又在 rel 属性中添加一个带方括号的组名. 例如:
<a href="images/image-1.jpg" rel="lightbox[roadtrip]">image #1</a>
<a href="images/image-2.jpg" rel="lightbox[roadtrip]">image #2</a>
<a href="images/image-3.jpg" rel="lightbox[roadtrip]">image #3</a>
********************************************
********************************************
基本上就是这么用,我都写的快吐血了
要是还有不明白的,提出来,需要详细代码的话,我可以给你做一个demo
lightbox下载地址:http://www.blueidea.com/articleimg/2006/08/3904/lightbox2.02.zip
prototype.js下载地址(你只需要下在lightbox就可以了,里面包含着个文件了):
http://www.prototypejs.org/