原文:The innovations of Internet Explorer
作者:尼古拉斯·泽卡斯(Nicholas C. Zakas) 翻译:@李松峰

早在Internet Explorer成为每个人对之都爱恨交加的浏览器以前,它曾是互联网创新的火车头。而自从IE6坠落为Web开发人员的“祸根”后,人们便很少记起IE原来做过的那些好事。信不信由你,IE4-6曾经像今天的浏览器一样,为Web开发做出过重大贡献。大量专有特性后来成了事实标准,最后又进入HTML5规范成为官方标准。如果说我们今天很多习以为常的特性都是拜IE所赐,你可能会大惊失色。不过,只要简单回顾一下历史,你就会发现这是真的。

enter image description here

DOM

如果IE是让人又爱又恨的浏览器,DOM(Document Object Model,文档对象模型)就是让人又爱又恨的API。你可以说DOM实在太烦琐,可以说它不适合JavaScript,还可以说它很荒谬。不管你怎么说,都没错。但是,DOM提供了一个机制,让开发人员能通过JavaScript访问网页的每一个元素。曾经有一段时间,人们只能通过JavaScript访问网页中特定的元素。Internet Explorer 3和Netscape 3只允许以编程方式访问表单元素、图像和链接。Netscape 4的情况有所好转,支持通过document.layer编程访问其专有的<layer>元素。Internet Explorer 4则更进一步,允许通过document.all编程访问页面中的每一个元素。

某种意义上讲, document.all其实是document.getElementById()的滥觞,或者说是它最早的版本。到现在,你仍然可以使用document.all,通过元素ID取得元素(比如,document.all.myDivdocument.all["myDiv"])。它们的主要区别是,Internet Explorer提供的是一个集合,而不是函数,与当时的document.imagesdocument.forms等一致。

Internet Explorer 4也是第一个支持通过标签名取得同类元素列表的浏览器,它提供了document.all.tags()。不管怎么说,它都是document.getElementsByTagName()的先驱,而且原理完全一样。如果你想得到所有<div>元素,可以使用document.all.tags("div")。即使在Internet Explorer 9中,这个方法仍然存在,但只是document.getElementsByTagName()的别名。

Internet Explorer 4还为我们提供了应用最广??的专有DOM扩展:innerHTML。看来,微软的人也知道以编码方式手工构建DOM有多痛苦,所以就帮我们实现这个快捷方式,当然还有outerHTML。实践证明,这两个属性极有价值,因此进入了HTML5标准(1)。无独有偶,针对纯文本的innerTextouterText也被证明很有价值,因此DOM Level 3新增了textContent(2),与innerText相似。

按照同样的思路下,Internet Explorer 4还引入了insertAdjacentHTML(),是另一种向文档中插入HTML文本的方式。这个方法进入标准的时间有点晚,但也载入了HTML5规范(3),现已得到浏览器广泛支持。

事件

开始的时候,JavaScript没有事件系统。Netscape和Microsoft都想实现这个事件模型,结果分别拿出了不同的方案。Netscape的方案是事件捕获,即先把事件分派到窗口,然后再给文档,最后交给预定目标。Netscape 6之前只支持事件捕获。

Microsoft的方案正好相反,他们提出了事件冒泡。他们认为,事件应该从实际的目标开始,然后传播到父元素,最后才到文档。Internet Explorer 9之前只支持事件冒泡。虽然官方的DOM事件规范涵盖了事件捕获和事件冒泡,但大多数Web开发人员还是只用事件冒泡。至于事件捕获,只会在一些JavaScript库为解决个别难题时技巧性地派上用场。

除了提出事件冒泡模型外,Microsoft还创造了一系列事件,最终都成为标准。

  • contextmenu:在元素上使用辅助鼠标按钮时触发。最早出现在Internet Explorer 5中,后来进入HTML5(4)。现在得到了所有主流桌面浏览器支持。
  • beforeunload:在unload之前触发,允许你阻止页面卸载。最初在Internet Explorer 4中引入,现在进入了HTML5(4)。也得到了所有主流桌面浏览器支持。
  • mousewheel:使用鼠标滚轮(或类似装置)时触发。支持这个事件的第一个浏览器是Internet Explorer 6。跟其他事件一样,它现在也进入了HTML5(4)。唯一不支持它的主流桌面浏览器是Firefox(但支持替代的DOMMouseScroll事件)。
  • mouseenter:类似mouseover,但不冒泡。由Microsoft在Internet Explorer 5中引入,以避免使用mouseover的不便。这个事件在DOM Level 3 Events中得到标准化(5)。Firefox和Opera也支持这个事件,但Safari和Chrome不支持(现在支持了吗?支持了——译者注)。
  • mouseleave:类似mouseout,但不冒泡;与mouseenter对应。在Internet Explorer 5中引入,也在DOM Level 3 Events中标准化(6)。与mouseenter得到的支持相同。
  • focusin:类似focus,但冒泡,以便于管理页面上的焦点变化。最初在Internet Explorer 6中出现,在DOM Level 3 Events中得到标准化(7)。目前未得到很好的支持,Firefox对这个事件的实现有一个bug尚未修复。
  • focusout :类似blur,但冒泡,以便于管理页面上的焦点变化。最初在Internet Explorer 6中出现,在DOM Level 3 Events中得到标准化(8)。与focusin一样,没有得到很好的支持,Firefox支持得还不错。

内嵌框架

内嵌框架最初是Netscape Navigator 2引入的专有特性,包括<frameset><frame><noframes> 。发明内嵌框架的想法很简单:那个时候,每个人都使用调制解调器上网,每次到服务器的往返都代价不菲。不如用一个内嵌框架加载只需加载一次的导航元素,然后通过它控制另一个内嵌框架,独立地加载不同内容。把导航放到独立的页面里,既可以节省服务器时间,也可以减少数据传输,加在一块节省的时间就很可观了。

在内嵌框架受到欢迎之后,Internet Explorer 3也开始支持它。但微软为此增加了自己的专有标签: <iframe> 。这个元素背后的想法是在一个页面中嵌入另一个页面。用Netscape的方案,要实现静态导航需要创建三个页面(导航页、内容页和框架集页),而在Internet Explorer中只要使用两个页面(包含导航的主页面和位于<iframe>中的内容页)。当初,这是Internet Explorer和Netscape Navigator的一个主要战场。

由于跟创建框架集相比工作量更少,<iframe>越来越流行。作为反击,Netscape在其第4版发明了<ilayer> ,与 <iframe>非常相似。当然,<iframe>赢了,现在已成为Web开发中一个重要组成部分。HTML4同时标准化了Netscape的内嵌框架和Microsoft的<iframe>,但Netscape的内嵌框架后来在HTML5中又被废弃(不建议使用)了。

XML与Ajax

虽然今天XML在Web上的应用并不像当初设想得那么广泛,但率先支持XML的还是Internet Explorer。它是第一个支持在客户端通过JavaScript解析XML和转换XSLT的浏览器。只可惜,它是通过ActiveX对象实现的XML文档和XSLT处理器。Mozilla开发团队清醒地意识到问题所在,因此就以DOMParserXMLSerializerXSLTProcessor的形式发明了类似的功能。其中前两个现在已经成为HTML5标准(9)。虽然基于标准的JavaScript XML处理机制与Internet Explorer的版本有很大不同,但它无疑受到了IE的影响。

在客户端处理XML从属于Internet Explorer对XMLHttpRequest的实现,后者作为一个ActiveX对象在Internet Explorer 5中首次??引入。当时的想法是,让网页从服务器获取XML文档,然后让JavaScript将其作为DOM来处理。Internet Explorer的版本要求使用new ActiveXObject("MSXML2.XMLHttp"),同时由于依赖版本字符串,又要求开发者必须通过层层测试才能使用最新版本。同样,Firefox又见义勇为,创造了当时还是专有的XMLHttpRequest对象,与Internet Explorer的版本具有完全相同的接口。随后,其他浏览器复制了Firefox的实现,最终导致Internet Explorer 7也创建一个非ActiveX的版本。当然, XMLHttpRequest正是后来Ajax革命的原动力,而Ajax革命点燃了所有人对JavaScript的激情。

CSS

一提到CSS,可能你不会对Internet Explorer有多少好感。毕竟,它在支持CSS方面总是那个拖后腿的(至少到Internet Explorer 10都是)。然而,Internet Explorer 3却是第一个实现CSS的浏览器。当时,Netscape正致力于实现另一个方案,叫JSSS(JavaScript Style Sheets,JavaScript样式表)(10)。顾名思义,就是用JavaScript来为页面设置样式。Netscape 4后来引入JSSS和CSS,落后Internet Explorer整整一个版本。但它的CSS实现并不好,往往要把样式转换为JSSS才能恰当应用(11)。另外,如果JavaScript被禁用,CSS在Netscape 4中也将无效。

虽然Internet Explorer对CSS的实现只限字体系列、字体大小、颜色和背景,但却十分可靠和称手。相比之下,Netscape 4的实现则bug丛生,让人感觉很难用。不错,在某种程度上,可以说Internet Explorer也为CSS的成功做出了贡献。

CSS的另一个重要的基本概念——盒模型,也受到了Internet Explorer的巨大影响。Internet Explorer 5最早实现的盒模型,把widthheight属性解释为元素的整体宽度和高度,包括内边距和边框。这也就是后来所说的border-box模型。W3C认为度量盒子大小的恰当方式是content-box ,即widthheight只包含内容区,而内边距和边框都是额外计算的。虽然Internet Explorer已经切换为使用符合标准的content-box模型,但Internet Explorer 8又新增了box-sizing属性,让开发者能切换回border-box模型。当然,CSS3标准化了box-sizing(12),但有些人,特别是Paul Irish,一直在建议开发者把box-sizing的默认值设为border-box(13)

Internet Explorer还为我们带来了以下CSS方面的创新,而且最终也都得到了标准化。

  • text-overflow:用于在文本内容超出其容器时显示省略号。第一次出现在Internet Explorer 6中,在CSS3中得到标准化(14)。现在得到了所有主流浏览器支持。
  • overflow-xoverflow-y:用于控制容器在两个不同方向的溢出行为。第一次出现在Internet Explorer 5中,后来正式纳入CSS3(15)。现在所有主流浏览器都支持。
  • word-break:用于指定字与字之间的换行规则。最早在Internet Explorer 5.5中出现,在CSS3中标准化(16)。除Opera之外其他主流浏览器都支持。
  • word-wrap:用于指定浏览器是否应在单词中换行。最早在Internet Explorer 5.5中实现,后来正式纳入CSS3 标准且改为overflow-wrap(17),但所有主流浏览器支持的还是word-wrap

此外,CSS3中许多新的视觉效果,都要感谢Internet Explorer奠定的基础。Internet Explorer 4中推出了专有的filter属性,使它成为具备如下能力的第一个浏览器:

  • 根据CSS指令生成渐变(CSS3:渐变)
  • 使用alpha滤镜创建半透明元素(CSS3:opacity和RGBA)
  • 把一个元素旋转任意角度(CSS3:transformrotate()
  • 给元素加阴影(CSS3:box-shadow
  • 给元素应用矩阵变换(CSS3:transformmatrix()

此外,Internet Explorer 4中曾有一个叫做过渡(transition)的功能,让你能用滤镜在页面上创建一些基本的动画。这些转场效果很多都借鉴自PowerPoint中常用的切换动画,如淡入、淡出、溶解,等等(18)

所有这些功能??都在CSS3中得到了标准化,只不过形式可能有所变化。1997年发布的Internet Explorer 4就具备了这些功能,而时至今日,这些功能才开始在其他浏览器中出现,真让人叹为观止。

对HTML5的其他贡献

Internet Explorer还为HTML5贡献了许多API,以下是本文尚未提到过的。

  • 拖放:原生拖放能力(19)可以说是HTML5中最酷的功能之一。这个API最早起源于Internet Explorer 5,HTML5在将它纳入标准时只作了非常少的修改。主要区别是增加了draggable属性,用于将任意元素标记为可拖动(Internet Explorer中用JavaScript调用element.dragDrop()做到这一点)。除此之外,该API与其原始镜像完全相同,而且也得到了所有主流桌面浏览器支持。
  • 剪贴板访问:现在已经从HTML5中脱离出来形成了独立规范(20),它支持在某些情况下赋予浏览器访问剪贴板的权力。这个API最初出现在Internet Explorer 6中,后来Safari如法炮制,但把原来window对象的clipboardData属性转移到了剪贴板事件的event对象上。HTML5后来采用了Safari的修订版,而目前这个API也得到了除Opera之外所有主流桌面浏览器支持。
  • 富文本编辑:富文本编辑使用的designMode属性是Internet Explorer 4引入的,源于Microsoft想为Hotmail用户提供更好的文本编辑体验。后来,Internet Explorer 5.5引入contentEditable属性,作为实现富文本编辑的简化方式。与这两个属性一起出现的是恐怖的execCommand()及其他关联方法。不管是好是坏吧,这个富文本编辑API也在HTML5中得到标准化(21),目前支持它的不仅有全部主流桌面浏览器,还有移动Safari和Android浏览器。

结论

说几句嘲弄Internet Explorer的话很容易,也很容易收到共鸣。但实际上,如果没有它的馈赠,就不会有我们今天所看到的Web。假如没有XMLHttpRequestinnerHTML,那Web开发会走向何方?它们都是Web应用发展过程中引发Ajax革命的绝佳催化剂,有赖它们很多新功能才得以崭露头角。看看这个已经成为众矢之的“坏浏览器”,再想想如果没有它也就没有今天的Web,一种令人啼笑皆非的感觉不禁涌上心头。

没错,Internet Explorer有它的缺点,但在互联网历史的大多数时间里,它都是那个推动技术进步的浏览器。身处众多浏览器互相竞争、踊跃创新的今天,我们很容易忘记来时走过的路。所以,下一次你再遇到Internet Explorer开发人员,请不要再对他们辱骂和扔西红柿了,试着说声感谢吧,感谢他们塑造了今天的互联网,也感谢他们让Web开发成为世界上最重要的一个职业。

更新(2012年8月23日):根据Sergio的留言,加入了对box-sizing的介绍。根据Paul的留言,加入了对<iframe>的介绍。

IE3-6贡献汇总

领域IE3IE4IE5/5.5IE6
DOMdocument.images
document.forms
document.links
document.all
document.all.tags()
innerHTML
outerHTML
innerText
outerText
insertAdjacentHTML()
--
事件-beforeunload
contextmenu
mouseenter
mouseleave
mousewheel
focusin
focusout
内嵌框架iframe---
XML与Ajax--XMLHttp-
CSS最早实现filter
transition
border-box模型
box-sizing
overflow-x
overflow-y
word-break
word-wrap
text-overflow
HTML5-designMode拖放
contentEditable
剪贴板访问

参考文献

  1. innerHTML in HTML5
  2. textContent in DOM Level 3
  3. insertAdjacentHTML() in HTML5
  4. Event Handlers on Elements (HTML5)
  5. mouseenter (DOM Level 3 Events)
  6. mouseleave (DOM Level 3 Events)
  7. focusin (DOM Level 3 Events)
  8. focusout (DOM Level 3 Events)
  9. DOMParser interface (HTML5)
  10. JavaScript Style Sheets (Wikipedia)
  11. The CSS Saga by H?kon Wium Lie and Bert Bos
  12. box-sizing property (CSS3 UI)
  13. * { box-sizing: border-box } FTW (Paul Irish)
  14. text-overflow property (CSS3 UI)
  15. overflow-x and overflow-y (CSS3 Box)
  16. word-break (CSS3 Text)
  17. overflow-wrap/word-wrap (CSS3 Text)
  18. Introduction to Filters and Transitions (MSDN)
  19. Drag and Drop (HTML5)
  20. Clipboard API and Events (HTML5)
  21. User Interaction – Editing (HTML5)