现如今使用HMTL5开发一个网站或者应用程序是一件令人望而生畏的工作。尽管各大主流浏览器厂商对HTML5的支持越来越完善,但是很少有开发者能够幸运到自己的程序只在这些支持良好的浏览器中运行,浏览器碎片化问题(译者注:即浏览器有多个版本,相互之间存在功能的差异或者兼容性问题,导致应用无法在跨越不同浏览器上正常使用)迫使职业的web开发者不得不耗费大量的精力在理想的功能和当前的现实之间找到平衡。好消息是 IE 9 和 10 都已经支持HTML5 了,用户可以抛弃旧版的 IE 浏览器了,但是作为开发者仍旧需要考虑浏览器兼容性问题。

然而这并不意味着在你要放弃使用HTML5,有很多技术可以来完美实现譬如屏幕尺寸或者CSS相关功能的的兼容性问题,所以关于HTML5的兼容性问题或许也可以得到完美解决。虽然老版本的浏览器缺少对HTML5新API的支持,但是JS是一门很灵活的语言,可以用来追加许多原生不支持的功能;

跨浏览器支持

使用HTML5一个非常棘手的问题就是我们不得不考虑对旧版本浏览器的支持,而这些浏览器对HTML5新API的支持很少甚至完全不支持。一想到采用新的网页技术引发的浏览器兼容、难以维护的分支代码、浏览器嗅探以及一系列其他问题就让我们抓狂。但是我们有一个名不转经传的技术,它可以缓解刚才我们提到的问题带来的影响并且允许你开发新的API,就好像你的用户在一夜之间把自己的浏览器升级了一样,这就是我们要说的polyfills。

Polyfills是Remy Sharp提出的一个术语,用来补充因缺乏对新API支持而缺失的功能。你可以使用它编写单独的应用而不用担心浏览器兼容性问题。实际上Polyfills并非新技术也不是绑定在html5上面的,在诸如json2.js, ie7-js等已经使用了这项技术。而不同的是现在增加了对HTML5的支持。

如何才算得上Polyfills

现在举一个实际的例子来说明我们刚才讨论的问题,在json2.js有这样一段,

 if (typeof JSON.parse !=='function') {// Crockford’s JavaScript implementation of JSON.parse
}

使用 typeof 测试这段代码,如果浏览器有原生的执行 JSON.parse,那么 json2.js 就不会去干扰或者重定义它。如果原生的 API 不可用,json2.js 就会执行一段 JavaScript 脚本来实现,它和原生的 JSON API 是完全兼容的。最后你可以在网页上使用 json2.js 而且不用考虑浏览器运行的是哪种代码。这显示出了 polyfilling 的优势 - 不仅是兼容方面,更是提供了一种接近标准 API 的执行方式。除此之外,不需要再知道那些站点的特有代码或者考虑兼容层的存在。最后的效果就是老版本的浏览器也可以像支持新API一样来使用这些新的功能。

HTML5新的语义元素

HTML5中最容易被Polyfills的就是它的新增的语义元素,比如<article>, <aside>, <header > and <time>,这些元素和历史悠久的<div>、<span>节点在呈现效果上没有太大的区别,但是他们被赋予了更加丰富、特别的语义。因为这些元素是标准通用标记语言(SGML),所以好处就是:像 IE6 这样的旧浏览器也能够显示他们。不过 IE浏览器有个奇怪的特性就是它只使用那些它承认的 CSS 样式。因此,即使旧的 IE浏览器显示了 HTML5 的新语义元素,但是如果它不支持html5它仍会忽视那些用户自定义的样式。幸运的是Sjoerd Visscher找到了一个变通方案,John Resig又把它发扬光大:在使用任意元素形式的时候调用 document.createElement(),这样就可以让 IE 浏览器运用 CSS 中所有的样式了。

我们来看个例子,这个例子中我们在head节点中调用document.createElement("article")来迫使ie浏览器应用用户自定义的css样式。

<pre name="code" class="html"><html><head><title>HTML5 Now?</title><style>article { margin: 0 auto; width: 960px; }</style><script>document.createElement('article');</script></head><body><article><!-- TODO: Write article… --></article></body></html>

看下效果在IE6中的效果

如果把document.createElement("article")注释掉CSS就不起作用了

但是这个解决办法不是那么的简便,我们总不能为每一个HTML5新增的语义元素都写脚本语句,所以需要找一个其他的解决办法,这时候我们就可以用到polyfills,在这个例子中我们可以用到一个名为html5shim(也就是所谓的html5shiv)的脚本库,

引入这个脚本库之后我们可以实现向例子一一样的效果但是要简便的多。

<html>
<head><title>HTML5 Now!</title><style>article { margin: 0 auto; width: 960px; }</style><!--[if lt IE 9]><script src="script/html5.js"></script><![endif]-->
</head>
<body>
<article><!-- TODO: Write article… -->
</article>
</body>
</html>

另外一个选择

如果你对 HTML5 非常感兴趣而在读这篇文章,相信你可能已经了解使用 Modernizr 了。不过你可能还不知道 Modernizr 其实已经内建了 html5shim 功能

持久的客户端存储

多年以来,在解决浏览器的状态存储问题时除了整合各大浏览器厂商特定的DOM组件和私人开发的插件外我们似乎别无他法。这些解决方案中有火狐的globalStorage,IE的userData,cookies,浏览器插件有类似flash和Google Gears等,尽管可以解决问题但是这些解决方案难以维护并且易出错。

为了解决这个问题在HTML5中增加了基于标准的用以进行客户端存储的API:localStorage,这个API提供了客户端/服务器端持久存储的键值对,它最多允许用户在一个网站中存储5M的独立数据。你可以把它想象为一个容量巨大的cookies,而且无需在http请求的时候在浏览器和服务器进行来回传递。localStorage 特性是那些需要浏览器专有数据项目最完美的搭档,就像记住偏好和本地缓存的远程数据。关于本地存储的发展历程可以看

现在所有高级的浏览器都已经支持 localStorage 特性了, IE8 也包括在其中,不过在 旧一些的版本中就不支持了,同时,还是有相应的polyfill解决方案可以让旧版的浏览器也支持这样的特性。从简朴的 RemySharp 的 Storage polyfiller 到可以向下兼容的 store.js 和 PersistJS,还有 LawnChair 的全功能 API 和 AmplifyJS 存储模块。

下面这个例子就是你可以使用AmplifyJS存储模块在不使用cookies的情况下存储用户在浏览器中的信息,即使是用户使用的IE6也可以起作用。

// Sets a localStorage variable 'Name' with my name in it.
amplify.store('name', 'Dave Ward');
var website = {name: 'Encosia',url: 'http://encosia.com'
}
// The library takes care of serializing objects automatically.
amplify.store('website', website);

而取出存储的信息也十分简便

// The values we stored before could then be used at a later time, even
//  during a different session.
var $personLink = $('<a>', {text: amplify.store('name'),href: amplify.store('website').url
});
$personLink.appendTo('body');

再次强调,使用localStorage或者基于localStorage的API的优势是它不像cookies一样需要在每次http请求的时候在浏览器和服务器之间传递,而且它不会自动把数据发给服务器,仅在本地保存,它使在不影响网站性能的情况下存储大量数据成为可能。而且对于支持离线应用的网站也能提供很好的支持。

用什么

Remy Sharp 的Storage Polyfiller 是唯一一个可以有资格作为localStorage的 polyfill 使用的,因为其他的js库无分完全吻合的模拟localStorage。不过不管怎样,store.js 和 AmplifyJS 存储模块提供了很大范围的旧浏览器兼容支持,这点很难被忽视

定位

HTML5的定位功能Polyfill支持现在也已经很成熟。如果浏览器都和操作系统都支持定位而且它们的设备上都配有 GPS 传感器,HTML5 提供的定位 API 的功能可以允许 JavaScript 代码判断你的页面是从何处访问的。

移动设备是最让人惊讶的基于浏览器的地理位置使用示例。将内置的 GPS 硬件模块和现代浏览器整合起来很好的支持了 HTML5 的定位 API,Android 和 iOS 设备都支持 HTML5 定位,而且和原生应用一样准确。

js可以像这样获取定位信息

navigator.geolocation.getCurrentPosition(function(position) {var lat = position.coords.latitude;var long = position.coords.longitude;console.log('Current location: ', lat, log);
});

定位功能在移动设备上被应用的很好,但是桌面设备通常不会配备 GPS 传感器,我们也都习惯了。不过那些在我们身边很常见的基于位置的广告们他们已经比地理位置 API 存在的时候长多了。因此在缺乏硬件支持的桌面浏览环境下获取地理位置也是可以的。

JavaScript 目前的做法是在已知的 IP 位置库中寻找访问者的 IP 地址。这种做法显然没有使用 GPS 设备精确,不过这些数据库通常能够准确定位区域位置,这对于很多应用来说已经足够了。

你或许已经知道无GPS 的更精确的地理位置定位不仅仅依赖查找 IP 地址。 通常来说这些增强定位准确性的方法都是借助 Wi-Fi 热点的位置库来协助完成的。不幸的是,目前浏览器中运行的 JavaScript代码不能够从系统底层调用信息。所以, polyfill 目前不可以使用基于 Wi-Fi 的技术,我们只可以使用 IP查找来代替。

Paul Irish 写了一个可以为旧浏览器和缺少 GPS 传感器的硬件提供定位的简单的地理位置 polyfill。它使用了谷歌的地理位置 API 来将用户的 IP 地址转换成相近的物理地理位置。它是一个真实的 polyfill,它将地理位置功能加入到了 navigator.geolocation对象中,不过只是在浏览器原生没有提供地理位置 API 的情况下使用。

浏览历史和导航

简单的DHTML效果提供了更加结构化的客户端特性,例如基于 AJAX 的分页和单页界面,这些结构变化放弃了和浏览器内置的导航和历史功能同步。当用户很自然的尝试用他们的返回按钮回到上一页页面或者应用的状态的时候,事情就不那么好了。我们搜索“禁用返回按钮”就会发现这个问题对现代网页开发的坏影响有多少了。

操作浏览器地址的“Hash”部分可以帮助我们解决部分问题。因为Hash原本就是用来在同一个页面中在不同的导航点之间跳转,更改链接的Hash值不会让页面像更改到相关的链接前缀那样刷新。利用Hash值允许客户端和JavaScript驱动的改变同步来保持浏览器显示的地址,这样就不需要使用传统的导航事件了。

ohashchange 事件

当操作浏览器Hash部分被很好的支持了,甚至连在 IE6 上都是,直到最近一个标准的监控Hash变化的方法才变得难以捉摸。最近的新浏览器支持了 onhashchange 事件,当地址的Hash部分改变的时候它就被触发了 -  可以完美的检测用户想通过浏览器的导航控制改变客户端状态的情况。可惜的是,onhashchange 事件只有相对较新的浏览器才支持,从 IE8 和 Firefox 3.6 之后都支持。

虽然 onhashchange 事件并不支持旧的浏览器,不过有可以为旧浏览器提供一个抽象的层的库文件。这些兼容的层使用浏览器特有的属性来复制标准的 onhashchangge 事件,甚至可以每一秒监控 location.hash 好多次,并且当地址Hash值在浏览器中改变的时候作出响应。

一个不错的选择是 Ben Alman 的 jQuery Hashchange 插件,这是他从自己开发的很流行的 jQueryBBQ 插件中提取出来的。 Alman 的 jQueryHashchange 提供了一个非常深层的跨浏览器的 hashchange 事件兼容性。我有点犹豫要不要把它称为 polyfill,因为这需要 jQuery 而且不能够准确的复制出原生 API ,不过当你的页面已经使用了 jQuery 的时候它真的很棒!

超越 HashState

操作Hash值是一个解决客户端状态管理问题的好方法,不过它还是有缺点的。自从基于Hash值的链接会让用户迷惑并且和页面上已有的导航冲突,控制浏览器导航特性就不是最好的方法了。

一个更根本的问题是浏览器并没有将Hash部分的浏览器请求加入到 HTTP 请求中。没有访问链接中的Hash位置,所以没可能立即返回到用户给页面加书签、通过邮件接收或者通过社交网络分享后相同的状态。这导致了网站只可以显示它们的默认页面,初始状态接着再通过一个别扭的转换跳转到期望的位置。为了证明这点在使用性上的影响,你只要看一下 Twitter 和 Gawker Media 的 “hash bang”重设计。

输入 pushState

幸运的是,HTML5 引入了一对明显提高了客户端历史管理方案的更先进的 API。通常被称为 pushState,它和 windows.history.pushState 方法和window.onopstate 事件结合起来的,它提供了异步处理整个浏览器地址路径部分和在对Hash之外的导航事件响应的方法。

在 Github 上查看项目的代码是现实中正在使用 pushState 最佳的示例。因为通过 pushState 处理浏览器的地址不会像传统地址改变那样刷新整个页面,Github 可以在每个代码页面切换之间提供过渡动画,链接还是用户友好的,而不是Hash标签或者查询字符串。

更好的是,如果你将其中一个链接保存为书签,之后再访问这个链接的时候,Github 会在你第一次请求的时候就立刻给你正确的内容,因为客户端中的链接就和服务器端的链接结构是一样的。就像我前面提到的那样,使用基于Hash的链接是不可能实现这些的,因为服务器和Hash部分的请求是无关的。

你的代码中使用 onhashchange 和 pushState

可惜的是,要想将浏览器不支持的 pushState 特性通过真正的 polyfill pushState 加入进去是不可能的。没有抽象层可以改变在旧浏览器中改变链接会让浏览器跳转和加载页面的事实。不过你可以在支持 pushState 的浏览器中使用它而在不支持的旧浏览器中使用基于Hash部分的链接。

Benjamin Lupton 组建了一个很棒的跨浏览器库,可以有效的解决在管理客户端历史时候遇到的大范围的诡异和不一致的现象。这个库可以用在从 IE6 到最新版的 Chrome 上。使用方法也非常简单。它有一个和 HTML5 自有的 pushState  语法很接近的语法:

// This changes the URL to /state1 in HTML5 browsers, and changes it to
//  /#/state1 in older browsers.
History.pushState(null, 'State 1', 'state1');
// Same as before, but /state2 and /#/state2.
History.pushState(null, 'State 2', 'state2');

相比准确模拟 HTML5 popstate 事件,history.js 包含了许多种类的适配器可以和那些库里的事件系统协调运行。例如,使用jQuery 适配器,你可以 一个事件处理程序和 history.js 的 statechange 事件绑定起来,就像这样:

History.Adapter.bind(window, 'statechange', function() {// Get the new history state from history.js.var state = History.getState();// Write the URL we’ve navigated to on the console.console.log(state.url);
});

通过 history.js 的pushState 方法,statechange 事件处理程序会在每次浏览器导航到通过 history.js 的 pushState 方法维持的历史节点的时候触发。不论是原生就支持 pushState 的 HTML5浏览器 还是仅支持基于链接Hash部分改变的旧浏览器都会监控这个事件,捕获每次活动。

将这个运用到现实应用中非常简单。你可以想象到将它用在和 AJAX 提供的表格分页和排序中,或者甚至是整站的导航(例如 Gmail 和 Twitter),它们不需要依靠那些大家都很厌恶的Hash链接和重定向。

使用 pushScissors 运行

使用 pushState 有一件需要注意的事,那就是你必须保证服务器端可以正确的你在客户端适应的每个链接。因为很容易你建立一个客户端的链接你的服务器用一个 404 或者 500 错误响应(举例,/未定义),这样很好的保证了你的服务器端在发送或者进行URL重写的时候尽可能优雅的处理意想不到的链接。例如,如果你有一个多页的报告在 /报告下,使用了 pushState 分成了 /报告/1,/报告/2,/报告/3 等等这么多页,你就要保证服务器端的代码可以优雅的对 /报告/未定义 这样的链接响应。

另外一个稍次一点的可选方案是在你的 pushState 地址中使用查询字符串的链接片段,就像 /报告?页码=2 和 /报告?页码=3。这样最终的链接看起来可能不太好看,不过最起码它们不会导致404错误。

接下来去哪里

这篇文章只讲到了 HTML5 polyfill 的一些皮毛。有不少提供了跨浏览器支持如 SVG 和 Canvas 图像,HTML5视频,ECMAScript 5 甚至 WebWorkers 特性的项目。如果你很有学习更多关于这些项目的兴趣,查看下面提供的奇妙的资源吧: https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills

原文链接:https://msdn.microsoft.com/en-us/magazine/jj131727.aspx

参考:

http://blog.csdn.net/wang16510/article/details/8960312

http://www.w3school.com.cn/html5/html_5_webstorage.asp

http://blog.csdn.net/fangaoxin/article/details/6952954

HTML5 Now: 深入了解HPolyfills相关推荐

  1. html5代码转换为视频,HTML5中的视频代码详解

    摘要 腾兴网为您分享:HTML5中的视频代码详解,智学网,云闪付,易推广,小红书等软件知识,以及360win10,流量魔盒,fitbit,上港商城,安卓2.3.7,全民惠,五年级下册英语单词表图片,t ...

  2. HTML5与CSS3权威指南之CSS3学习记录

    title: HTML5与CSS3权威指南之CSS3学习记录 toc: true date: 2018-10-14 00:06:09 学习资料--<HTML5与CSS3权威指南>(第3版) ...

  3. HTML5调用手机的Datepicker(日期选择器)

    HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证,包含了如下新的输入类型: email url number range Date pickers (date, month, ...

  4. android h5弹窗,Android嵌套html5页面中alert 弹出框问题

    最近项目中遇到一个头疼的问题,那就是在安卓里嵌套html5的时候发现alert弹出框出现了问题 那就是弹出的时候会出现串 来自http://xxxxx 网页的提示 然后下面出来具体的弹出信息,还有更奇 ...

  5. HTML5 本地文件操作之FileSystemAPI整理(二)

    一.文件目录操作 1.DirectoryEntry对象 属性: 1.isFile: 操作对象的是否为文件,DirectoryEntry对象固定其值为false 2.isDirectory: 操作对象是 ...

  6. Notepad++支持jQuery、html5、css3

    Notepad++里的代码提示文件是以XML文件存放于目录 ....\Notepad++\plugins\APIs\下的. 将这三个文件:html.xml, css.xml, javascript.x ...

  7. 使用按钮控制HTML5背景音乐开关

    <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name ...

  8. [重磅] 让HTML5达到原生的体验 系列之中的一个 避免切页白屏

    非常多人都想.甚至曾使用HTML5开发跨平台App.而且想达到原生App的体验. 最后的结果都是无奈的放弃.HTML5貌似美好,但坑太多.想做到原生App的体验差点儿不可为. 也曾有过著名的faceb ...

  9. html5 FileReader初识

    使用html5的FileReader可以实现多媒体文件的预览功能,代码如下: <html> <head> <script type="text/javascri ...

  10. html页面视频标签,html5基础标签(html5视频标签 html5新标签用法)

    点评:html5基础,包括html5视频标签和html5新标签等标签用法,大家参考使用吧 1.  声明的变化 2.  指定字符编码的变化,html5中建议使用utf-8 3.  Html5中允许 没有 ...

最新文章

  1. 漫画:三种 “奇葩” 的排序算法
  2. ssh 在远程主机执行本地脚本
  3. linux bin模式,binlog有哪些工作模式?Linux云计算运维入门
  4. 问题 B: C语言11.2
  5. 介绍Linux中cp直接覆盖不提示的方法
  6. React Hooks的使用(一)——useState、useEffect解析
  7. 火了!堪称神级的 Spring Boot 手册
  8. 分数化小数(指定精度)
  9. w7 mysql不启动_Win7安装mysql5.7服务无法启动没有任何报错信息处理:
  10. Redis实现分布式爬虫
  11. 带你玩转Visual Studio(八)——带你跳出坑爹的Runtime Library坑
  12. 【Linux】修改镜像源
  13. android的自定义字体,Android中使用自定义字体的方法
  14. ask调制流程图_ASK调制及相干解调电路设计.doc
  15. 解决hash冲突的三种方法
  16. 中国芯绝配:普华推全新龙芯3A3000操作系统
  17. svn取消文件夹图标_TortoiseSVN文件夹及文件图标不显示解决方案
  18. 第一章概述-------第一节--1.5 计算机网络的类别
  19. ARM嵌入式开发板推荐
  20. Scala详细文本教学04

热门文章

  1. OSChina 周三乱弹 —— 迷宫里乱开宝箱的后果
  2. 网页形式的php抓取文件,PHP 抓取网页源文件
  3. 启动计算机按住del不放,电脑开机需要按del进入系统怎么办
  4. 学fpga(先自顶而下设计,再自下而上集成)
  5. springboot tmp目录生成机制
  6. 毛纲源-考研数学(数学一)常考题型及其解题方法技巧归纳--华中科技大学出版社
  7. cosc2406数据库辅导assignment
  8. Codingame平台“CHUCK NORRIS”的Python实现
  9. ThreatScan-免费的网站在线安全检测平台_TScan
  10. ARCore从零到一 (1) 搭建开发环境