预览 IE10 支持的 HTML5 特性

  • 崔康

2011 年 8 月 16 日

话题:Java.NETRubyWeb框架JavaScript微软最佳实践架构HTML5DevOps语言 & 开发

从 IE8 开始,微软就逐步在浏览器中增加对HTML5的部分支持,如今 IE10 已经推出了几个预览版,Web 开发人员关心的是在 IE10 中,哪些 HTML5 特性获得了支持,由此会影响到技术选型和职业发展等重要问题。在本文中,我们根据微软发布的相关特性梳理一下 IE10 对 HTML5 的支持情况。

目前,IE10 预览版支持的 HTML5 特性可以概括为以下几点:

下面我们来详细了解一下各个 HTML5 特性的支持情况。

异步脚本执行

随着 Web 2.0 技术的发展,浏览器端脚本承载了越来越多的计算任务,这对于传统上单线程运行的浏览器来说,遭遇了性能的瓶颈。用户在碰到类似的网页时,经常会看到类似“脚本运行缓慢,是否继续运行”的提示框。为此,HTML5 考虑到了 Web 开发人员的需求,提供了一些解决方案。其中我认为最重要的两个分别是 async 属性和 Web Workers(稍后提到)。

script 元素的 async 属性允许相关的脚本与页面的其他部分异步加载和执行。也就是说,脚本可以在后台加载和运行,而不影响页面的解析工作。对于包含密集处理脚本的页面来说,async 属性能够显著提高页面加载的性能。

async 属性是W3C HTML5 标准的一部分,设计的应用场景是:不依赖于某个脚本,但是该脚本仍然需要尽快执行。在微软的文章中举了这样一个需要 async 属性的例子:

Lilah 的个人博客使用了大量基于脚本的小组件。这些组件用于增强访问者的体验,但是她的页面在不加载这些组件的情况下也能正常运行(支持禁用脚本的浏览器用户)。目前,她在 HTML 文件的顶部加载所有小组件,但是读者抱怨说页面加载时间太长,因为脚本执行的缘故。她尝试把脚本移到页面的底部来提高速度,但是由于小组件内容太多,这种修改过程太繁琐。她真正想做的是让这些组件尽可能快的加载,但是不要阻碍页面上的其他内容。经过快速搜索后,她发现 HTML5 的 async 属性符合自己的需求。通过把所有基于脚本的小组件放在一个外部文件中,她可以在基于脚本的功能增强和性能之间取得更好的平衡:

<head>

    <title>Lilah's Blog</title>

    <script async src="widgets.js"></script>

</head>

IE10 的预览版支持 script 元素的 async 和 defer 属性。defer 属性在早期的 IE 中就被引入,那么这两个属性在用法上有什么区别吗?微软给出了四种可能的组合(无论是 async 还是 defer 属性,都必须在 src 属性存在的情况下才起作用),请读者仔细地体会 async 和 defer 之间的细微差别:

<script src="widgets.js"></script> 脚本立即执行,页面等待脚本完成之后再继续解析。这种方式会显著降低页面加载性能。
<script async src="widgets.js"></script>

脚本下载与页面解析异步进行。脚本在下载完成后执行。

<script defer src="widgets.js"></script> 页面完成解析后脚本再执行。
<script async defer src="widgets.js"></script> async 优先,忽略 defer 属性。这种方式可以帮助开发人员在支持 async 属性的浏览器中使用 async,在不支持 async 的浏览器中退化为支持 defer。

HTML5 拖放 (Drag and Drop)

拖放功能在桌面客户端软件中应用十分普遍。HTML5 标准对拖放做了规定,IE 和之前的版本支持dataTransfer对象和拖放图片、超链接、文本的事件。IE10 预览版对所有元素增加了draggable属性,并且支持把一个或多个文件从桌面拖放到网页上。draggable 属性支持你将任意 HTML 元素设为页面可拖放的。它提供了如下状态:

draggable = 'true' 该元素可拖放。
draggable = 'false' 该元素不可拖放。
draggable = 'auto' 该元素遵循默认的浏览器行为(文本、超链接和图片可拖放,其他元素不能)。

例如,下列代码支持用户拖放元素。

<button id="mybutton" draggable="true">Drag me</button>

<img src="photo.png" draggable="true" />

<div id="mydiv" draggable="true">Moveable text</div>

当用户拖动一个可拖放的元素时,IE10 预览版随着拖动的光标移动显示一个元素的虚影。draggable 属性是不可继承的,因此元素的子元素不会自动变成可拖放的。

除此之外,dataTransfer 对象的 files 属性支持你把文件从桌面的文件夹中拖放到网页上。这种方式能够减少一些应用,如邮件客户端,把附件拖放进邮件内容中,或者在图库页面中添加照片。这种从桌面端到 Web 端的无缝交互无疑是 Web 开发的一大亮点。

下面的事件监听器和 dropHandler 函数展示了如何创建一个网页区域让用户拖放文件上去。其中的“dropspot”可以是 div、image,或者其他元素。dragover 和 drop 事件调用了 doNothing() 函数避免默认的事件处理和冒泡,否则可能会导致不可预知的结果。

// this function runs when the page loads to set up the drop area

function init()

{

 // Set the drop-event handlers

 var dropArea = document.getElementById("dropspot");

 dropArea.addEventListener("drop", dropHandler, false);

 dropArea.addEventListener("dragover", doNothing, false);

}

function dropHandler(event)

{

 // use our doNothing() function to prevent default processing

 doNothing(event);

 // get the file(s) that are dropped

 var filelist =  event.dataTransfer.files;

 if (!filelist) return;  // if null, exit now

 var filecount = filelist.length;  // get number of dropped files

 if (filecount > 0)

 {

   // Do something with the files.       

 }

}

// Prevents the event from continuing so our handlers can process the event.

function doNothing(event)

{

 event.stopPropagation();

 event.preventDefault();

}

File API

IE10 预览版引入了对 File API 的支持。File API来自于 w3c 的草案,表示 web 应用中的文件对象,并且可以编程选取它们并访问数据。File API 目前正在被 W3C Web 应用工作组标准化。通过该 API,web 开发人员可以在客户端机器上以安全地方式访问本地文件,而无需扩展或者插件。

File API 支持浏览器在用户授权的情况下读取和处理文件。此外,File API 在无插件的情况下支持更流畅的文件上传体验,包括上传进度的状态反馈等。

在下面的 W3C File API 示例中,不同的代码片段分别处理进展、错误和成功条件:

function startRead() {

// Obtain input element through DOM.

var file = document.getElementById('file').files[0];

if(file) {

  getAsText(file);

}

}

function getAsText(readFile) {

var reader = new FileReader();

// Read file into memory as UTF-16    

reader.readAsText(readFile, "UTF-16");

// Handle progress, success, and errors

reader.onprogress = updateProgress;

reader.onload = loaded;

reader.onerror = errorHandler;

}

function updateProgress(evt) {

if (evt.lengthComputable) {

  // evt.loaded and evt.total are ProgressEvent properties.

  var loaded = (evt.loaded / evt.total);

  if (loaded < 1) {

    // Increase the progress bar length.

    // style.width = (loaded * 200) + "px";

  }

}

}

function loaded(evt) {

// Obtain the read file data.  

var fileString = evt.target.result;

// Handle UTF-16 file dump

if(utils.regexp.isChinese(fileString)) {

  //Chinese Characters + name validation.

}

else {

  // Run other charset test.

}

// xhr.send(fileString)   

}

function errorHandler(evt) {

if(evt.target.error.code == evt.target.error.NOT_READABLE_ERR) {

  // The file could not be read.

}

}

其他文件相关的改进包括带有文件类型过滤的多文件上传。在下例中,多个 GIF 或者 JPEG 文件可以被用户选择:

<input type="file" name="pic" multiple accept="image/gif, image/jpeg" />

HTML5 表单和输入验证 

IE10 预览版增加了对新HTML5 输入类型和属性的支持。这些支持帮助开发人员可以通过很少的脚本来快速、简便的提供用户提示和输入验证。在 HTML5 的输入类型和属性出现之前,检查手机号码没有包含字母,或者验证邮件地址正确输入,都需要开发人员编写额外的代码。HTML5 客户端表单和输入验证帮会组开放人员关注其他任务而不是构建验证函数。

新 URL 和 email 输入类型

新 HTML5 输入类型支持提供了内建的 URL 和 email 输入类型。URL 输入元素接受完全合格的地址,例如http://www.contoso.com。同样,email 输入类型接受标准的 email 格式,如joe@contoso.com。在下面的例子中,如果用户不正确地输入了 URL 或者 email 地址,IE 就会显示错误信息。

<input type="url" name="url"/>

<input type="email" name="email"/>

新输入属性

IE10 预览器提供了对新HTML input 属性的支持,如 required、pattern 和 placeholder 能够帮助开发人员确保用户在网页中输入所需的、正确的数据。

  • required 属性

required 属性表示该元素必须填写值才能提交。该属性能够用于 text、text area、URL、email、select、checkbox 或者 radio button 等元素。这是一个 Boolean 属性。当用户的鼠标悬停在 required 区域时,他们会看到相应的必填提示,如果设定了 title 属性,那么会显示该值。

<form id="yourname">

<label>Enter your first name:

  <input name="firstname" type="text" required><input type="submit" value="Go"/>

</label>

</form>

如果用户尝试在不填写该区域的情况下提交表单,他们会收到错误信息,而且键盘焦点会置于为填写的区域中。

  • pattern 属性

pattern 属性允许你定义一个正则表达式要求用户的输入必须匹配。pattern 属性支持 text、search、url、email 和 password 等输入元素。

<form>

<label>

    <input type="tel" name="tel" pattern="\(\d\d\d\) \d\d\d\-\d\d\d\d"

     title="enter a telephone number in   the format (xxx) xxx-xxxx"/>

    <input type="submit"/>

</label>

</form>

  • min、max 和 step 属性

min、max 和 step 属性适用于 input type=number。min 和 max 定义了数据的最小值和最大值。step 属性定义了开发人员允许的跳跃值。例如,如果 min=0,step=1,那么 0、1、2、3...... 是允许的。如果 min=1.1,step=1,那么 1.1、2.1、3.1...... 是允许的。下面的例子展示了输入区域要求 0 到 10 之间的偶数。任何此范围之外的数据或者奇数都不能提交,而且会显示错误消息。

<form>

<label>Enter an even number between 0 and 10:

  <input type="number" min="0" max="10" step="2"/>

  <input type="submit"/>

</label>

</form>

  • placeholder 属性

占位符属性,在 web 开发中很常见,通过设置该属性,用户能够在输入区域看到“虚拟”的示例,直观明了,也减轻了开发人员的负担。IE10 预览版支持对该属性做样式化定制,包括属性值的文本颜色、背景颜色、字体等等。

  • autofocus 属性

自动聚焦属性帮助开发人员设置页面加载后的光标位置,无须用户主动点击某个输入控件。该属性只能用于页面的单个元素,如果同一页面的多个元素都设置了 autofocus 属性,那么只有第一个元素起作用。

  • 大小写开关提示

该功能之前已经广泛应用于桌面客户端应用,比如用户输入密码时,如果打开了大小写开关(Caps lock ),那么应用会弹出对话框提示。IE10 预览版加入了该项提示功能,无须开发人员编写任何代码,该功能在大小写开关打开的时候即自动触发提示。

HTML5 解析

IE10 预览版完全支持 HTML5 的解析算法,不断完善与其他浏览器的一致行为。这些努力包括支持 SVG-in-HTML、HTML 语义元素、保留未知元素的结构和改善对空格的处理。

IE 团队在 HTML 解析器上的目标是让所有的 HTML 在跨浏览器中解析行为一致。这可能是因为 HTML5 是第一个完整定义 HTML 解析规则的标准,细致到最边缘的情况和错误条件。即使 HTML 标记是无效的,HTML5 仍然定义了如何解析它,IE 10 遵循了这些原则。这种跨浏览器的一致行为使得开发人员在创建应用解析 DOM 元素时,不必把过多精力花费在单独处理 IE 的“异常”行为。下面的解析例子展示了这些改进中修补的部分情况。

HTML DOM ( HTML5 + IE10 ) DOM ( IE9 )
<b>1<i>2</b> |- <b>

   |- "1"

   |- <i>

     |- "2"

|- <b>

   |- "1"

   |- <i>

   |- "2"

  |- <i>

<p>Test 1

<object>

<p>Test 2

</object>
|- <p>

  |- "Test 1\n"

|- <object>

  |- "\n "

  |- <p>

    |- "Test 2\n"
|- <p>

  |- "Test 1\n"

|- <object>

  |- "\n "

|- <p>

  |- "Test 2\n"

除此之外,因为早期 IE 的一些特性无法与 HTML5 解析兼容,它们已经从 IE10 预览版中删除。用户在使用 IE10 的 legacy compatibility 模式访问依赖这些陈旧特性的网站时不会出现问题。通过这种方式,现在正常运行的网站即使没有时间和资源来更新自己,那么网站依然可以在 IE10 中工作。

条件注释

条件注释在当前的跨浏览器 Web 开发中使用广泛,成为大家判断某项特性是否支持的重要判断方法,但是它们只适用于 IE 的老版本。

<!--[if IE]>

This content is ignored in IE10 Platform Preview and other browsers.

In older versions of Internet Explorer, this renders as part of the page.

<![endif]-->

如果需要区分浏览器,请使用feature detection ,例如下面的代码示例:

function registerEvent( sTargetID, sEventName, fnHandler )

{

  var oTarget = document.getElementById( sTargetID );

  if ( oTarget != null )

  {

     if ( oTarget.addEventListener ) {   

        oTarget.addEventListener( sEventName, fnToBeRun, false );

     } else {

       var sOnEvent = "on" + sEventName;

       if ( oTarget.attachEvent )

       {

          oTarget.attachEvent( sOnEvent, fnHandler );

       }

     }

  }

}

这种新式判断方式逐渐成为兼容性开发的主流,其优点在于不再依赖于条件注释,而是通过判断所需特性本身是否存在来做进一步的处理。

HTML5 沙箱

IE10 预览版支持沙箱属性,确保对包含不可信内容的iframe元素的安全限制。这些限制通过防止不可信内容执行导致潜在恶意行为的操作提高安全性。

为了启用这些限制,在元素中设置 sanbox 属性,如下所示:

<iframe sandbox src="frame1.html"></iframe>

当 sanbox 属性在 iframe 元素中指定时,iframe 元素中的内容称为被置于沙箱中。沙箱中的 iframe 元素,如下行为受到限制:

  • 沙箱内容不能打开弹出窗口和新浏览器窗口。某些方法如 createPopup()、showModalDialog()、showModelessDialog() 等会失败(无反馈)。
  • 超链接不能在新窗口打开。
  • 沙箱内容被认为来自于单一域,防止对受到同源策略保护的 API 的访问,如 cookie、local storage 和其他文档的 DOM。
  • 顶级窗口不能被沙箱内容导航。
  • 沙箱内容不能提交表单数据。
  • 插件 (object、appletembed 或者frame) 不能实例化。
  • 自动的元素行为被禁用,包括meta元素的刷新、input控件的自动聚焦和audiovideo元素的自动播放

Web Workers

IE10 预览版开始支持 Web Workers。Web Workers API提供了一种在后台运行脚本的方式。

传统上,浏览器都是单线程的,强制应用中的所有脚本都在一个 UI 线程中统一运行。虽然你可以通过使用 DOM 时间和setTimeout API 来创建若干任务同时执行的假象,但是计算密集型任务会对用户体验造成严重的伤害。

Web Worker API 为 Web 应用开发者提供了一种启动后台脚本并与主页面并发运行的方式。你可以同时创建多个线程用于长时间运行的任务。新的 Worker 对象需要一个.js 文件,通过对服务器的异步请求包含进来。

var myWorker = new Worker('worker.js');

进出 worker 线程的所有通信都通过消息管理。主 worker 和其他 worker 都可以利用postMessage 发送消息,并利用onmessage事件监听响应。消息的内容作为事件的data 属性发送。

下面的例子创建了一个 worker 线程并监听消息。

var hello = new Worker('hello.js');

hello.onmessage = function(e) {

alert(e.data);

};

worker 线程发送消息:

postMessage('Hello world!');

Web Worker 之间的双向通信

要建立双向通信,主页面和 worker 线程都监听 onmessage 事件。在下面的例子中,worker 线程在一定的延迟之后返回消息。首先,脚本创建 worker 线程。

var echo = new Worker('echo.js');

echo.onmessage = function(e) {

alert(e.data);

}

消息内容和超时值在表单中指定。当用户点击提交按钮,脚本把两个值传递给 worker 线程。为了防止页面在新的 HTTP 请求中提交表单值,事件处理器也调用了 preventDefault 函数。请注意你无法发送对 DOM 对象的引用给 worker 线程。Web Workers 对它们能够访问的数据做了限制。只有 Javascript 原始数据类型,如 Object 或者 String 值允许。

<script>

window.onload = function() {

var echoForm = document.getElementById('echoForm');

echoForm.addEventListener('submit', function(e) {

  echo.postMessage({

    message : e.target.message.value,

timeout : e.target.timeout.value

});

e.preventDefault();

}, false);

}

</script><form id="echoForm">

<p>Echo the following message after a delay.</p>

<input type="text" name="message" value="Input message here."/><br/>

<input type="number" name="timeout" max="10" value="2"/> seconds.<br/>

<button type="submit">Send Message</button>

</form>

最后,worker 线程监听消息并在指定的超时间隔后返回响应。

onmessage = function(e)

{

setTimeout(function()

{

  postMessage(e.data.message);

},

e.data.timeout * 1000);

}

在 IE 10 预览版中,Web Worker API 支持如下方法和事件:

方法 描述
void close(); 终止 worker 线程。
void importScripts(in DOMString... urls); 逗号分隔的其他 Javascript 文件列表。
void postMessage(in any data); void postMessage(in any data);

通道消息

IE10 预览版引入了通道消息 (Channel Messaging),支持在不同的浏览器情境中直接通过端口通信。该特性来自于HTML5 Web Messaging标准。在创建端口之后,两边结合 postMessage 函数和 onmessage 事件来通信。

打开通道,创建 MessageChannel 对象:

var channel = new MessageChannel();

通道对象包含 port1 和 port2 两个端点。通常情况下,一个端点口作为本地端口,另一个发远程窗口或者 worker 线程。端口也可用于 worker 线程之间的通信。

下面的例子是发送端口用于跨文档通信。请注意端口数组必须是最后一个参数。

otherWindow.postMessage('hello', 'http://example.com', [channel.port2]);

同样,你可以通过 postMessage 发送端口给 worker 线程,如下:

worker.postMessage({code:"port"}, [channel.port2]);

端口数组在事件的 port 属性中发送。端口可以使用一次并关闭,也可以保存到本地重复使用。下面的例子显示了 worker 线程如何接收和使用端口。

// Worker Thread

onmessage = function (event) {

  if (event.data.code == "port") {

      event.ports[0].postMessage("Port received.");

  }

}

端口收到后,进一步的通信利用 postMessage 和 onmessage 事件实现。下面的代码定义了事件处理器并发送利用通道端口发送消息。

channel.port1.onmessage = function (event) {

// Message is in event.data

alert("Message is: " + event.data);

}

channel.port1.postMessage('hello');

本文只是汇总了 IE10 预览版对 HTML5 特性的支持,未来 IE10 正式版的具体情况我们还要拭目以待。长久以来,IE 因其“我行我素”的风格受到 Web 开发人员的诟病,如今随着 HTML5 的标准化进程推进,IE 团队也在努力追赶时代的脚步,特别是在 Chrome 和 Firefox 通过快速发布的方式抢占浏览器市场份额的严峻形势下,IE10 的特性成为社区关注的焦点。感兴趣的读者可以从这里下载 IE10 平台预览版,并通过微软的Test Drvie 项目中查看 HTML5 在 IE 中的演示程序。

注:本文涉及的所有代码示例均引自微软官方网站。

Java.NETRubyWeb框架JavaScript微软最佳实践架构HTML5DevOps