從IE8開始,微軟就逐步在瀏覽器中增加對HTML5的部分支持,如今IE10已經推出了幾個預覽版,Web開發人員關心的是在IE10中,哪些HTML5特性獲得了支持,由此會影響到技術選型和職業發展等重要問題。在本文中,我們根據微軟發佈的相關特性梳理一下IE10對HTML5的支持情況。
目前,IE10預覽版支持的HTML5特性可以概括爲以下幾點:
- 異步腳本執行(Asynchronus Script Execution)
- 拖放(Drag and Drop)
- File API
- 表單驗證(Forms Validation)
- HTML5解析(HTML5 Parsing)
- 沙箱(Sandbox)
- Web Workers
- 通道消息(Channel Messaging)
下面我們來詳細瞭解一下各個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(event), 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格式,如[email protected]。在下面的例子中,如果用戶不正確地輸入了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> |
<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、applet、embed或者frame)不能實例化。
- 自動的元素行爲被禁用,包括meta元素的刷新、input控件的自動聚焦和audio、video元素的自動播放。
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中的演示程序。