在JavaScript的世界里,有两个词经常被提到,shim和polyfill.它们指的都是什么,又有什么区别?。
一个shim是一个库,它将一个新的API引入到一个旧的环境中,而且仅靠旧环境中已有的手段实现。
一个polyfill就是一个用在浏览器API上的shim.我们通常的做法是先检查当前浏览器是否支持某个API,如果不支持的话就加载对应的polyfill.然后新旧浏览器就都可以使用这个API了.术语polyfill来自于一个家装产品Polyfilla:。
Polyfilla是一个英国产品,在美国称之为Spackling Paste(译者注:刮墙的,在中国称为腻子).记住这一点就行:把旧的浏览器想象成为一面有了裂缝的墙.这些[polyfills]会帮助我们把这面墙的裂缝抹平,还我们一个更好的光滑的墙壁(浏览器)。
Paul Irish发布过一个Polyfills的总结页面“HTML5 Cross Browser Polyfills”.es5-shim是一个shim(而不是polyfill)的例子,它在ECMAScript 3的引擎上实现了ECMAScript 5的新特性,而且在Node.js上和在浏览器上有完全相同的表现(译者注:因为它能在Node.js上使用,不光浏览器上,所以它不是polyfill).。
Polyfills是一种保证使用现代代码的绝佳办法,同时还能支持旧版浏览器。但是目前polyfills使用起来很困难,因此我们开发了一种全新的服务以便简化其使用方法。在此,邀请读者使用并改进它。
挑战
下面是我们正在尝试解决的一些问题:
开发者对哪些特性需要使用polyfill不是很清楚。例如你在某个旧版本的IE浏览器(因为你有很大数量的用户还在使用它)中载入网站,发现网站不工作,你不得不慢慢调试来搞清楚到底是哪个特性导致了这个问题。有时候问题很清楚,但大多时候并非如此,尤其是旧版浏览器往往缺少好的开发者工具的时候。
针对每个特性都有很多polyfill可供选择。很难确定哪一个能最忠实地模拟缺少的特性。
有一些大的polyfill捆绑着很多你不需要的polyfill,例如ES6,它全面覆盖了一系列的特性集。为了解决一个简单的问题而向浏览器植入所有的这些代码其实是不必要的。
较新版本的浏览器不需要polyfill,但一般来说polyfill可用于所有种类的浏览器。虽然这是为了提高与旧版浏览器的兼容性,但这也降低了新版浏览器的性能。我们不愿意做出这种妥协。我们更愿意在原本不具备某个特性的浏览器上使用polyfill。
我们的解决办法:以polyfill为服务。
为了解决这些问题,我们开发了polyfill服务。这有点像是验光师先对你的眼睛验光检查,然后针对你的视力问题配置眼镜。我们将对浏览器做同样的事情。下面解释它是如何工作的:
开发人员在他们的页面中插入一个脚本标记作为导入polyfill服务的端点。
该服务分析浏览器的user-agent标头和必需特性列表(或是使用一个默认的可使用polyfill服务的列表),然后搭建浏览器所需的polyfill列表。
按照正确的依赖顺序表定制polyfill。
通过CDN 压缩服务包并提供服务(对此我们衷心感谢Fastly的支持)。
我们真的需要这个解决办法吗?你可以这样思考:Modernizris是一个大型的特性检测包,所有对它的合理使用都得益于自定义的安装配置,但是很大数量的Modernizris用户仅仅使用了它的默认安装,这常常是来自于 cdnjs.com 或是 html5boilerplate 的某个部件。但是,如果不使用Modernizris的特性检测功能,那你为什么安装这个工具呢?可能你误解了库文件的功能,单纯地以为Modernizris会“修补东西”?不得不承认,第一次听到这个名字的时候笔者正是这样想的,以至于后来发现Modernizris不但没有起到作用,反而拖了现代浏览器的后腿,笔者感到有些失望。
然而,Polyfill服务却是真正起到了作用。不想花时间去深入了解旧版本浏览器缺点的你一点儿错也没有。让别人先弄明白问题所在,然后我们在不需要了解细节的情况下就能直接受益。
如何使用
最简单的使用情况是:
<script src="//cdn.polyfill.io/v1/polyfill.min.js" async defer></script>。
这包含了我们默认的 polyfill设置。这个默认设置是我们人工挑选的一个特性列表,我们认为这个列表中所包含的特性对于现代网络开发来说不可或缺,而且相对应的polyfill相当小且十分精确。如果你想指定添加某个polyfill特性,只需要这么做:
<!-- Just the Array.from polyfill --><script src="//cdn.polyfill.io/v1/polyfill.min.js?features=Array.from" async defer></script>。
<!-- The default set, plus the geolocation polyfill --><script src="//cdn.polyfill.io/v1/polyfill.min.js?features=default,Navigator.prototype.geolocation" async defer></script>。
如果有必要在解析自己的代码之前加载polyfill的话,你可以移除async和defer属性,或是使用一个脚本加载器(不需要任何polyfill的加载器!)
测试与文档特性支持
我们所支持特性的完整表格在特性矩阵中。为了搭建这个网格,我们使用了Sauce Lab的自动测试平台,它截获了polyfill在每个浏览器中的测试,然后记录结果。
User-Agent 分析? 你确定?
是的,我们确定。下面是为什么UA分析要比特性检测好的原因:
在一些情形中,针对同一特性我们有多个polyfill可供选择,这是因为一些浏览器提供非顺从实施方式,因此只需要你敲打成型即可,而其他浏览器则没有提供任何的实施。但若是有UA检测,你能够选择相应的polyfill。
有了UA检测,第一个HTTP请求就能直接由polyfill代码应答。如果我们使用了特性检测,第一个请求将会为特性检测代码服务,而第二个请求则需要用于获取特定的polyfill。
几乎所有的大型网站都使用UA检测。这并不是说与之相关的特征就是不好的。显然,好的UA规则要比差劲的UA规则更难编写。而且我们并没有排除借助特性检测使用该服务的可能。
angularjs支持ie9的,但是代码的兼容写法如下:
为确保Angular应用在IE上能够工作请确认:
1. 在IE9或更早的版本上polyfill JSON.stringify。可以使用JSON2或JSON3来polyfills。
<!doctype html>。
<html xmlns:ng="http://angularjs.org">。
<head>。
<!--[if lte IE 7]>。
<script src="/path/to/json2.js"></script>。
<![endif]-->。
</head>。
<body>。
...
</body>。
</html>。
2. 在连接处将id="ng-app"添加到根元素,使用ng-app属性。
<!doctype html>。
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">。
...
</html>。
3. 不能使用自定义的元素标记,像<ng:view>(使用属性版本<div ng-view>来代替),或。
4. 如果必需要用自定义元素标记,然后必须采取以下步骤以确保IE9及之前版本都能用:
<!doctype html>。
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">。
<head>。
<!--[if lte IE 9]>。
<script>。
document.createElement('ng-include');。
document.createElement('ng-pluralize');。
document.createElement('ng-view');。
// Optionally these for CSS。
document.createElement('ng:include');。
document.createElement('ng:pluralize');。
document.createElement('ng:view');。
</script>。
<![endif]-->。
</head>。
<body>。
...
</body>。
</html>。
5. 使用ng-style标记来替代style="{{ someCss }}"。后续的版本能够在Chrome和Firefox下工作但不能在IE版本<=11下工作(在撰写本文时的最新版本)。
下面就是规范中的描述
The details element represents a disclosure widget from which the user can obtain additional information or controls.。
— WHATWG HTML5 specification 。
理论上我们可以用它创建那种折叠的小组件,用户可以有打开和关闭的交互.在<details>我们可以放入我们任何想放入的内容.。
浏览器的支持情况
在我们开始之前,实际一点,让我们看看目前浏览器的支持情况,目前只有chrome支持 <details > 元素.Opera很快就会支持Opera will support it soon,让我们来用chrome演示这种效果吧.。
<details 的使用方法。
这里有两个相关的元素:<details>和可选的。
让我们来看下面的代码:
1 2 3 4 <details> <summary>Show/Hide me</summary> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </details> 。
你可以通过下面的链接察看效果see this in action over at jsbin.这是一个简单的例子但是可以将效果完美展现的代码,没有任何Javascript.。
OPen 属性
在上面的例子中,在页面加载的时候内容是隐藏的。我们可以将<detail>默认的视觉属性通过布尔值作修改,让其当我们加载页面的时候是展开的:
1 2 3 4 <details open> <summary>Show/Hide me</summary> <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </details> 。
注意,这里并没有 closed 属性,因为只要你移除 open 属性,执行的就是 closed 属性效果。
<summary>元素。
我们已经简要的看了
的作用。因为它是短语内容,我们可以使用内联 (inline)标签 <span;>。我们为什么会有这种想法呢?也许这样子能更方便的通过而外样式控制显示效果或者像 spec 建议的那样:为一个表单元素增加一个 <label>标签。如果他能生效的话,至少能让我很顺手:
1 2 3 4 <details> <summary><label for="name">Name:</label></summary> <input type="text" id="name" name="name" /> </details> 。
常理看,我们点击 summary 的任何位置都应该展开 <detail>元素的内容。但是在这个例子中,我们点击<summary>并没有展开内容,因为你点击的是<label>他会将焦点放到 <input>标签-即使那部分内容被隐藏在<details>标签。
很明显,在这点需要更好的声明,你认为这个地方应该发生什么事情呢?可能某个浏览器生产商能看一下这个效果。
<details>元素多层嵌套。
你可以在<details>中嵌套<details>,可以完美的案例查看这个效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 <details> <summary>Question 1</summary> <p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p> <details> <summary>Related documents</summary> <ul> <li><a href="#">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</a></li> <li><a href="#">Aliquam tincidunt mauris eu risus.</a></li> <li><a href="#">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</a></li> <li><a href="#">Aliquam tincidunt mauris eu risus.</a></li> </ul> </details> </details> 。
使用案例
在哪些情况时会用到 <details>?FAQ表可能是我们最先涌现的想法。大家经常使用手风琴效果是用在FAQ列表,所以 <details> 是这一效果的最佳效果。
考虑到这一系列内容,它可能被固定在某一区域,当我们滚动内容的时候。像这样子?
你也可以使用<details>来操作博客的评论内容,用户简介,下载列表,复杂的表单,或者像规范中描述下面的应用:
An example of the <details> element from the spec 。
实际上,只要你看看我写的wordpress,会发现有大量的使用 <details>的机会。让我们在评论中了解一下你的观点和想法。
样式格式化
你如何对这个定义样式?同时,在webkit浏览器中我们可以使用伪类样式 ::-webkit-details-marker。你可以看到这个小的案例:
1 2 3 4 5 details summary::-webkit-details-marker { background: red; color: #fff; font-size: 500%; } 。
我们也可以将这个小组件定位。这里是向右浮动的这就是我们初始化效果。
我们如何将默认的组件Icon自定义呢?那就是用 属性选择器 (attribute selector),你可以用来检测 <details>元素是打开的还是关闭的,然后为其定义一个合适的背景图片。我们咋下面的例子中作了一个类似的效果,使用 :after pseudo-element元素定义成我们喜欢的背景图片:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 summary::-webkit-details-marker { display: none } summary:after { background: red; border-radius: 5px; content: "+"; color: #fff; float: left; font-size: 1.5em; font-weight: bold; margin: -5px 10px 0 0; padding: 0; text-align: center; width: 20px; } details[open] summary:after { content: "-"; } 。
在上面的例子中,我们使用文本 “+”和“-”来定义这个组件的状态,根据你的设计需要,你可能希望使用 :before来代替 :after,这两个为类元素都可以使用 image.。
details的[open]属性选择器能创造很多有意思的可能性。因为我们是好医生,下面是我们装饰后的效果,下面是截屏效果:
Styled <details> element in Chrome 。
如果我们可以用过css的动画效果来修饰打开和关闭时的状态,这样设计就更完美了,但是目前为止我们还没有办法做到这点。
可访问性
不幸的是在我们写这篇文章的时候,<details>h还无法通过键盘访问,Steve Faulkner 写到:
Bottom line is, currently no keyboard support and no usable information exposed to assistive technology.。
自己试一下,如果你使用鼠标打开 <details> 元素,你可以使用键盘到达内容部分,但是你无法使用键盘打开和关闭区域。所以目前这并不是理想状态,不过我们相信这个小国很快会被改进。
向后兼容
在我们抱怨其在IE6中无法生效之前,感谢这些聪明的人们,我们可以提供优雅的像狗兼容。这些效果也被列在下面的网站very handy collection of cross-browser polyfills,这两个都需要 jQuery:。
<details> fallback via jQuery by Mathias Bynens 。
Another <details> alternative, also based on jQuery by Manuel Bieh 。
1 2 3 4 5 <script> if (!("open" in document.createElement("details"))) { alert("No details"); } </script> 。
更新:感谢的评论。上面的代码并不是100%可靠,因为他在某些chrome版本下会失败。你可以使用this Modernizr snippet。
我们为何使用这种类型的交互?
言归正传,为什么会有这个效果在HTML5中?就像其它HTML5的效果,使用这种效果能够更简单。比如时间选择,Date pickers, sliders, progress indicators, 现在这种手风琴效果就可以在不使用JavaScript的情况下更方便实施。谁能想到下一个是什么?如果是 tabs 标签那就好了。
总结
在这篇文章中,我们阐述了如何去使用<details>和<summary>元素。<details>是一个新元素,通过和<summary>元素通过浏览器可以创造手风琴的交互效果。
目前,<details>只能在 Chrome 工作,不过我们期待这会在不久的将来有所改变。这里只有一个css trick我们可以使用 ::-webkit-details-marker,但是我们拥有很多的其它css。让我们在评论中知道关于<details>元素你在这方面的经验和想法。
需要兼容IE10的话需要在polyfills.ts文件,把。
/** IE9, IE10 and IE11 requires all of the following polyfills. **/。
这行注释下面的代码打开