polyfill html
关于HTML5的最顽固的错误观念之一是,它在未来几年实际上将无法使用。 有了这个神话,而且浏览器对HTML5的新功能的支离破碎的不确定性,现在很容易找到有理由避免使用HTML5的人。
但是,尽管某些功能在法律上还没有准备好在生产中使用,但HTML5中的许多新API已经固化,足以在更新的浏览器(例如Chrome,Firefox 4和Internet Explorer 9)中依赖。事实上,即使Internet Explorer 6也包括对以下功能的支持: HTML5的“新”功能之一, contentEditable
。 更重要的是,HTML5中的许多新功能引人注目,以至于再等十年再开始使用它们就没有意义了。
跨浏览器支持
迈向HTML5的最大难题是我们大多数人别无选择,只能支持各种旧浏览器,而这些浏览器几乎不支持最有用的新API。 采用新的Web技术的想法会引起跨浏览器不一致,分支代码无法维护,浏览器嗅探以及许多其他问题的噩梦。 但是,有一种未被充分了解的技术可以完全缓解HTML5某些新功能的那些问题,并且仍然允许您针对新的API进行开发,就好像所有用户都在一夜之间升级了他们的浏览器:polyfills。
“ Polyfilling”是Remy Sharp创造的一个术语,用于描述一种以重复缺失API的方式回填缺失功能的方法。 使用此技术,您可以编写特定于应用程序的代码,而不必担心每个用户的浏览器是否都本机实现。 实际上,polyfill不是一项新技术,也不是与HTML5绑定的。 多年以来,我们一直在使用诸如json2.js,ie7-js之类的polyfills和各种后备技术,以在Internet Explorer中提供透明的PNG支持。 不同的是,去年HTML5填充材料的数量激增。
是什么使Polyfill制成?
有关我正在谈论的具体示例,请看json2.js。 具体来说,这是JSON.parse
实现中的第一行代码:
if (typeof JSON.parse !== 'function') {
// Crockford’s JavaScript implementation of JSON.parse
}
通过使用typeof
测试来保护代码,如果浏览器具有JSON.parse
的本机实现,则json2.js不会尝试干扰或重新定义它。 如果本机API不可用,则json2.js将以与JavaScript的本机JSON API完全兼容的方式实现JSON.parse
JavaScript版本。 最终,这意味着您可以在页面上包含json2.js,并有信心使用JSON.parse
而无需考虑代码在哪个浏览器中运行。
这表明了polyfilling方法的优点-不仅提供了一个兼容层,而且以一种试图紧密映射polyfill实现的标准API的方式来提供它。 因此,任何站点特定的代码都不需要知道或关心兼容性层的存在。 最终,这将产生更干净,更简单的特定于应用程序的代码,使您可以利用新的API,同时仍保持与旧版浏览器的兼容性。
HTML5的新语义元素
HTML5中最容易实现polyfill的新功能之一就是添加的语义元素集,例如<article>
, <aside>
, <header >
和<time>
。 这些元素大多数都完全按照古老的<div>
和<span>
进行渲染,但是它们赋予了更丰富,更具体的语义含义。
因为这些元素是有效的SGML,所以好消息是,即使是较旧的浏览器(如Internet Explorer 6)也将在今天显示它们。 但是,Internet Explorer的一个怪癖是它仅将CSS样式应用于其可识别的元素。 因此,即使旧版本的Internet Explorer确实呈现了HTML5的新语义元素的内容,它们在这样做时也会忽略任何用户定义的样式。
幸运的是,Sjoerd Visscher发现了Internet Explorer的一种简单解决方法,他的方法受到John Resig的欢迎 。 使用指定为参数的任意任意元素类型调用document.createElement()
会导致Internet Explorer识别该类型的元素,并按预期将CSS样式正确地应用于它们。
例如,在下面显示的文档的<head>
中添加对document.createElement('article')
的单个调用即可驯服Internet Explorer并强制其将CSS样式应用于<article>
元素。
<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>
对document.createElement
此调用更改了Internet Explorer应用CSS样式的方式。
当然,没有人愿意为HTML5中添加的大量新语义元素中的每一个手动添加createElement
语句。 提取繁琐的内容正是polyfill发光的地方。 在这种情况下,有一个名为html5shim (也称为html5shiv)的polyfill,它可以自动初始化Internet Explorer与新语义元素的兼容性的过程。
例如,上面的代码可以重构为使用html5shim,如下所示。
<html>
<head>
<title>HTML5 Now!</title>
<style>
article { margin: 0 auto; width: 960px; }
</style>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<article>
<!-- TODO: Write article… -->
</article>
</body>
</html>
使用html5shim polyfill
请注意围绕脚本引用html5shim的条件注释。 这样可以确保只能在早于版本9的Internet Explorer版本中加载和执行polyfill。在已经为新元素提供适当支持的浏览器中,不会浪费时间下载,解析和执行此代码。
要考虑的另一种选择
如果您对HTML5足够感兴趣,可以阅读本文,那么您可能已经知道或正在使用Modernizr。 但是,您可能不知道的一件事是Modernizr内置了html5shim createElement
功能。 如果您正在使用Modernizr进行特征检测,那么您已经具有HTML5语义元素的向后兼容性。
客户端永久存储
多年来,我们别无选择,只能将供应商特定的DOM扩展和专有插件结合在一起,以解决浏览器中长期状态持续存在的问题。 这些解决方案包括Firefox的globalStorage
,Internet Explorer的userData
,cookie以及Flash或Google Gears之类的插件。 这些可行的解决方法虽然可行,但它们乏味,难以维护且容易出错。
为了解决这个问题,HTML5中最受欢迎的附加功能之一是基于标准的API,用于将数据持久存储在浏览器中: localStorage
。 该存储API提供了一致的客户端-服务器键/值存储,该存储可以为用户访问的每个网站存储多达5 MB的隔离数据。 您可以将localStorage
视为一个庞大的cookie,它易于使用,并且在每个HTTP请求期间都不会在浏览器和服务器之间来回传输。 localStorage
功能非常适合需要特定于浏览器的数据的任务,例如记住首选项和本地缓存远程数据。
每个A级浏览器(包括Internet Explorer 8) localStorage
支持localStorage
功能,但是大多数浏览器的较早版本localStorage
提供该功能。 同时,已经出现了几种解决方案,可以将跨浏览器存储填充到那些较旧的浏览器中。 它们的范围从Remy Sharp的Storage polyfiller的简单性到store.js和PersistJS提供的全面向后兼容性, 再到 LawnChair的功能齐全的API和AmplifyJS存储模块 。
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
例如,这是您可以使用AmplifyJS存储模块在用户的浏览器中持久保存某些数据而无需使用Cookie的方法-即使该用户使用的是Internet Explorer 6:
// 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的localStorage
是,这些数据都不需要保存在cookie中,然后与每个HTTP请求一起传输,也不要求您调用Flash之类的重量级插件。只是存储一点数据。 数据存储在真正的隔离本地存储机制中,这使其非常适合在本地缓存数据或开发对脱机使用具有丰富支持的站点。
使用什么?
雷米·夏普(Remy Sharp)的Storage polyfiller是唯一真正有资格作为polyfill的产品,因为其他产品并不完全模仿HTML5 localStorage
API。 但是,store.js和AmplifyJS存储模块为更广泛的回退方法提供支持,以实现与旧版浏览器的兼容性。 实用上,这很难忽略。
地理位置
Geolocation
是另一个可以进行填充HTML5功能。 如果浏览器和操作系统都支持geolocation
,并且在具有GPS传感器的设备上运行,则HTML5可以访问geolocation
API,该API允许JavaScript代码确定从何处访问您的网页。
移动设备是基于浏览器的geolocation
最令人印象深刻的例子。 通过将其内置的GPS硬件与支持HTML5 geolocation
API的现代浏览器相结合,Android和iOS设备都支持原生HTML5 geolocation
,其精度与原生应用相同。
在这些最佳环境中访问geolocation
数据所需JavaScript如下所示:
navigator.geolocation.getCurrentPosition(function(position) {
var lat = position.coords.latitude;
var long = position.coords.longitude;
console.log('Current location: ', lat, log);
});
这对移动应用程序来说很好,但是桌面硬件通常不包含GPS传感器。 但是,我们都习惯了在桌面硬件上围绕Internet跟踪我们的位置感知广告的时间远远超过了地理定位API的存在时间,因此显然可以解决桌面浏览环境中缺少GPS的问题。
在JavaScript中,当前的解决方法是在已知IP位置的数据库中查找访问者的IP地址。 与使用GPS设备相比,该方法的准确性大大降低,但是这些数据库通常能够在正确的区域内定位IP地址,这足以用于许多应用程序。
您可能已经知道不仅仅依赖IP地址查找的更精确的无GPS地理定位技术。 大多数情况下,这些增强的估算是通过将可见的Wi-Fi热点标识符与数据库中过去特定物理位置的物理位置进行比较的新颖方法来完成的。
不幸的是,在浏览器中运行JavaScript代码当前尚无法获得操作系统中的数据。 因此,在可预见的将来,基于Wi-Fi的技术不适用于polyfills,这使我们只能使用IP查找。
保罗·爱尔兰 ( Paul Irish)编写了一个简单的地理位置polyfill ,可在较旧的浏览器和缺少GPS传感器的硬件上提供一定程度的geolocation
。 它通过使用Google的geolocation
API将访问者的IP地址转换为大致的geolocation
来实现此目的。 从将geolocation
功能插入navigator.geolocation
对象的意义上说,这是一个真正的polyfill,但前提是浏览器本身没有提供geolocation
API。
浏览器历史记录和导航
随着表面DHTML效果让位给更多结构化的客户端功能,例如基于AJAX的分页和单页界面,这些结构性更改开始与浏览器的内置导航和历史记录功能不同步。 然后,当用户直观地尝试使用其“后退”按钮导航到上一页或应用程序状态时,情况就会变得很糟。 搜索“禁用后退按钮”将揭示此问题困扰现代Web开发的程度。
操纵浏览器位置的“哈希”部分有助于解决问题的一方面。 由于哈希原本是用于在同一页面内的导航点之间跳转的,因此更改URL的哈希不会像更改基础URL前缀那样触发页面刷新。 利用哈希的该属性,客户端更新可以使浏览器的显示地址与JavaScript驱动的更改保持同步,而这些更改是在没有传统导航事件的情况下发生的。
onhashchange事件
虽然很好地支持操纵浏览器的哈希,但甚至可以追溯到Internet Explorer 6之前,用于监视哈希变化的标准化方法直到最近才变得难以捉摸。 当前的浏览器支持onhashchange
事件,该事件在地址的哈希部分发生更改时触发,非常适合检测用户何时尝试使用浏览器的导航控件来浏览客户端状态更改。 不幸的是, onhashchange
事件仅在相对较新的浏览器中实现,支持从Internet Explorer 8和Firefox 3.6版本开始。
尽管onhashchange
事件在较旧的浏览器中不可用,但是有些库在较旧的浏览器中提供了抽象层。 这些兼容性onhashchange
使用特定于浏览器的怪癖来复制标准的onhashchange
事件,甚至可以每秒监视几次location.hash
并在浏览器发生变化时做出React,而无需其他方法。 与此相关的一个可靠选择是Ben Alman的jQuery Hashchange插件,他从他流行的jQuery BBQ插件中提取了该插件。 Alman的jQuery Hashchange公开了具有非常深的跨浏览器兼容性的hashchange
事件。 我犹豫称其为polyfill,因为它需要jQuery,并且不能完全复制本机API,但是如果您已经在页面上使用jQuery,那么它的效果很好。
超越HashState
操纵哈希是解决客户端状态管理问题的一个良好的开端,但这并非没有缺点。 劫持合法的浏览器导航功能并不是最佳选择,因为基于散列的URL结构可能会给用户造成混乱并与现有的页面导航冲突。
甚至更根本的问题是浏览器在HTTP请求中不包括请求的URL的哈希部分。 如果无法访问URL的那部分,就不可能立即返回与用户添加书签,通过电子邮件接收或通过社交共享发现的页面处于同一状态的页面。 这就导致站点别无选择,只能以默认的初始状态显示页面,然后自动触发令人讨厌的过渡到用户实际期望的状态。 为了找到证据证明这对可用性有影响,您只需要对Twitter和Gawker Media的“哈希爆炸”重新设计产生广泛的负面React就可以了。
输入pushState
幸运的是,HTML5还引入了一对更高级的API,可以显着改善客户端的历史记录管理情况。 通常简称为pushState
, window.history.pushState
方法和window.onpopstate
事件的组合为异步操纵浏览器地址的整个路径部分以及对哈希之外的导航事件做出React提供了一种途径。
在GitHub上浏览项目的源代码是目前使用pushState
的最佳现实示例之一。 由于使用pushState
操纵浏览器的地址不会像传统的地址更改那样引起整页刷新,因此GitHub能够在代码的每个“页面”之间提供动画过渡,同时仍保留用户友好的URL哈希或查询字符串。
更好的是,如果您将书签保存到这些URL之一中并在以后直接导航到它,则GitHub能够在第一个请求上立即为您提供正确的内容,因为客户端URL结构与它们在服务器上使用的URL匹配。 正如我之前提到的,当您使用基于哈希的URL时,这样做是不可能的,因为您的Web服务器永远不会占用请求的哈希部分。
在自己的代码中使用onhashchange和pushState
不幸的是,要在不支持的浏览器中真正填充pushState
功能是不可能的。 没有任何抽象层可以改变以下事实:在较旧的浏览器中修改URL会触发页面加载。 但是,通过在实现该功能的浏览器中使用pushState
,然后在较早的浏览器中使用基于散列的方法,您可以兼得两全。
本杰明·拉普顿(Benjamin Lupton)组装了一个强大的跨浏览器库,以消除因维护客户端历史记录而引起的各种怪异和不一致之处。 他的库涵盖了从Internet Explorer 6到最新版本的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');
history.js并未公开HTML5 popstate事件的确切副本,而是提供了各种适配器来与这些库中的事件系统一起使用。 例如,使用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
方法pushState
历史记录点时,都会触发此statechange
事件处理程序。 无论是在本地支持pushState
HTML5浏览器中,还是在仅支持基于哈希的URL更改的旧版浏览器中,监视此单个事件都会捕获任何活动。
将其用于实际应用程序很容易。 您可能会想像将它与AJAX支持的网格分页和排序结合使用,甚至可以用于整个站点的导航(例如,Gmail或Twitter),而无需求助于那些普遍讨厌的哈希爆炸URL和重定向。
使用pushScissors运行
使用pushState
时需要注意的一件事是,您必须注意服务器将正确响应客户端上使用的每个URL。 由于建立服务器将以404或500错误响应的客户端URL很容易(例如/undefined
),因此,最好将服务器端路由或URL重写配置为尽可能优雅地处理意外的URL。 例如,如果在/report
report处有一个多页报告,每个页面的pushState
驱动的URL是/report/2
, /report/3
等等,则应确保服务器端代码能够优雅地响应对像/report/undefined
这样的URL。
一种不太理想的选择是在pushState
地址更新中使用querystring
URL片段,例如/report?page=2
和/report?page=3
。 产生的URL看起来不太好,但是至少不太可能导致404错误。
从这往哪儿走
本文仅涉及HTML5 polyfills生态系统的表面。 有活跃的项目为SVG和画布图形,HTML5视频,ECMAScript 5甚至WebWorkers等功能提供跨浏览器支持。 如果您有兴趣了解有关这些项目的更多信息,保罗·爱尔兰(Paul Irish)汇集了一个精彩的资源,其中包含简短的描述和指向其中许多链接的链接: https : //github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser- Polyfills 。
翻译自: https://www.sitepoint.com/html5-now-getting-more-through-polyfills/
polyfill html