傳統瀏覽器目前不會被完全取代,令你難以將最新的CSS3 或HTML5 功能嵌入你的網站。 Modernizr 正是為解決這一難題應運而生,作為一個開源的JavaScript 庫,Modernizr 檢測瀏覽器對CSS3 或HTML5 功能支持情況。 Modernizr 並非試圖添加老版本瀏覽器不支持的功能,而是令你通過創建可選風格配置修改頁面設計。 它也可以通過加載定制的腳本來模擬老版本瀏覽器不支持的功能。
Modernizr 簡單易用,但不是萬能的。 成功使用Modernizr 很大程度上取決於你的CSS 和JavaScript 技能。 通過本指南,你可以了解如何為不支持多欄或投影的瀏覽器設置可選風格。 此外,你還可以了解如何讓老版本瀏覽器對使用最新HTML5 要求(required)屬性的表單進行驗證,以及如何根據瀏覽器的功能有選擇地加載腳本文件。
Modernizr 是一個用來檢測瀏覽器功能支持情況的JavaScript 庫。 目前,通過檢驗瀏覽器對一系列測試的處理情況,Modernizr 可以檢測18項CSS3 功能以及40多項關於HTML5 的功能。 它比傳統檢測瀏覽器名稱(瀏覽器嗅探)的方式更為可靠。 一整套測試的執行時間僅需幾微秒。 此外,Modernizr 網站通過定制腳本只對你感興趣的元素進行檢測,從而實現效率優化。
當使用Modernizr 檢測CSS3 支持情況時,你無需具備任何JavaScript 的知識。 你僅需在網頁中插入文件,它隨即根據瀏覽器的功能情況在頁面的<html>標籤上添加一組類。 相應類的名稱已經符合標準化的要求並淺顯易懂。 例如,如果瀏覽器支持box-shadow 屬性,則需要添加相應的boxshadow 類;否則,添加一個no-boxshadow類即可。 你所要做的一切只不過是創建一個使用這些類的式樣表,以便為相應瀏覽器提供合適的式樣。
Modernizr 可輕鬆實現JavaScript 解決方案,即人們熟知的polyfills-它模擬HTML5 相關功能和技術,如地理定位。 然而,你的確需要對JavaScript 有基本了解以便使用這些功能和技術。 術語polyfill來源於一種填補裂縫的黏土的英國品牌Polyfilla(即美國人熟知的填泥料)。 這裡,polyfill 用來填補瀏覽器功能上的漏洞。 有時,Modernizr 可無縫地執行這項任務。 但本質上,這只是一種修補工作,所以,不能依賴它產生無漏洞瀏覽器所實現的完全相同結果。
與其它JavaScript 庫相同的是,Modernizr 可提供development 和production 版本。 與大多數庫相比,唯一的不同之處是,空格和註釋已經從production 版本中刪除了,這樣可以減少下載量的大小。 Modernizr 採取了不同的方法。 development 版本在某種意義上可稱為是廚房中的水槽—它幾乎包含了一切。 production 版本只包含了你選擇的那些元素,這樣能夠顯著降低下載量。 在很多情況下,production 版本可以縮小為development版本大小的二十分之一。
當使用Modernizr 進行測試時,我建議你下載development 版本。 一旦你掌握了它是如何運作的以及它的能力,你就可以下載一個自定義production 版本以便在你的網站進行部署。
本教程的示例文件包含的是Modernizr的development 2.0.6 版本,但是我建議你從Modernizr 站點上用最新更新的版本替代它。
注:如果你錯誤地單擊了主導航菜單中的Download 鏈接,那麼你將看到大量的複選框出現,要求你去選擇你想要的工具。 這是為定制的production 版本所設置。 單擊面板頂部的Development 版本的鏈接,或者單擊瀏覽器的Back 按鈕返回主頁並選中圖1所示的Development 按鈕。
如前所述,Modernizr 並沒有嘗試在舊版本的瀏覽器中添加新的功能,但是它允許你按照你的風格去彌補那些缺失的功能。 為了展示這是如何運作的,示例文件中包含了一個叫做css_support_begin.html 的頁面。如果你在新式瀏覽器中加載這個頁面,它應該看起來如圖2所示。
圖2. Firefox 5以多欄的格式顯示了頁面並且在圖像中添加陰影該頁面的風格是使用了CSS3的column-count和box-shadow屬性,以便以多欄的格式顯示文本並在圖像中添加陰影。 舊版本的瀏覽器不支持這些屬性中任何一項,因此在Internet Explorer (IE) 7 中同一頁面看起來如圖3所示。
在IE9中,同一頁面顯示了圖像陰影,但是文本和圖3中所示的佈局是一樣的。
你在嘗試彌補缺失的功能上採取什麼方式取決於你的設計大綱的要求。 要嘗試使頁面在所有的瀏覽器中看起來完全一樣將要涉及大量工作,但是你可以做一些簡單的改進,比如在圖像周圍環繞文字,調整圖像與文本的左邊距,以及在圖像底部和右邊緣添加隱約的邊界,以便使它更具三維立體的感覺。
Modernizr 使用JavaScript 檢測瀏覽器所支持的功能,但是,它並不是使用JavaScript 動態地加載不同的樣式表,而是使用非常簡單的技術將類添加到頁面的<html>標籤。然後作為設計者由你決定使用CSS 層疊為目標元素提供合適的樣式。例如,如果頁面支持box-shadow屬性,那麼Modernizr 會添加boxshadow類。如果不支持,那麼它用no-boxshadow類作為替代進行添加。
由於瀏覽器忽略它們無法識別的CSS 屬性,因此你可以放心地按照你的基本樣式規則使用box-shadow屬性,然而需要按照下面的格式為舊版本的瀏覽器添加單獨的descendant selector:
.no-boxshadow img { /* styles for browsers that don't support box-shadow */ }只有不支持box-shadow的瀏覽器才會有no-boxshadow類,因此其它的瀏覽器不會應用這個樣式規則。
讓我們將Modernizr 添加到示例頁面並檢查它添加到<html> 標籤中的類。
<!DOCTYPE HTML> <html> <!DOCTYPE HTML> <html class=no-js>Modernizr 依賴於在瀏覽器中啟用的JavaScrip。 當它啟用時,這種類會被動態地刪除。 但是,在極少數情況下,當JavaScrip 沒有啟用時,它依然存在於HTML makup 中,如果必要,它允許你為這樣的訪問者創建特殊的樣式規則。
</style> <script src=js/modernizr.js></script> </head>注:如果你使用Insert 面板或者Insert菜單,則Dreamweaver 會添加type=text/javascript到開始的<script> 標籤中。 這在HTML5 中不再要求,但是留著它並不會造成危害。
注:如果你的Dreamweaver 版本沒有Live Code(或者你正使用不同的HTML 編輯器),那麼你可以使用大多數新式瀏覽器提供的開發工具或者Firefox 瀏覽器提供的Firebug 檢查生成的代碼。
如圖4所示, no-js類已經被js類替代,這表明JavaScript 已經啟用。
表1列舉了Modernizr 使用的類名稱以表明對CSS3 的支持。 如果某個功能不支持,那麼相應類的名稱用no-作前綴。
表1. Modernizr 檢測的CSS3 功能
CSS 功能 | Modernizr 類(屬性) |
@font-face | fontface |
::before and ::after pseudo-elements | generatedcontent |
background-size | backgroundsize |
border-image | borderimage |
border-radius | borderradius |
box-shadow | boxshadow |
CSS animations | cssanimations |
CSS 2D transformations | csstransforms |
CSS 3D transformations | csstransforms3d |
CSS transitions | csstransitions |
flexible box layout | flexbox |
gradients | cssgradients |
hsla() | hsla |
multi-column layout | csscolumns |
multiple backgrounds | multiplebgs |
opacity | opacity |
reflection | cssreflections |
rgba() | rgba |
text-shadow | textshadow |
無論在哪對特定的CSS屬性進行測試,類的名稱和屬性名稱都是一樣的,然而這要求去除任何連字號或是括號。 其它類是按照它們參考的CSS3模塊而命名。
參見表1,你可以看到Modernizr使用boxshadow和csscolumns分別表明了對box-shadow屬性和多欄佈局的支持。 因此,你可以使用no-boxshadow和no-csscolumns類為不支持這些功能的瀏覽器創建特殊的樣式規則。
為了保證指令簡單,我將演示只有CSS 聲明的範例。 你可以直接地將它們鍵入到Code視圖中或者使用New CSS Rule對話框。
.no-boxshadow img創建一個新的descendant (compound) selector。 #8A8A8A )。 由此產生的樣式規則應該如下所示:.no-boxshadow img { border-right: #8A8A8A 2px solid; border-bottom: #8A8A8A 2px solid; }這不像半透明的陰影那樣有吸引力,但是儘管如此,它仍然使得圖像能夠從背景中略微地突起。
.no-csscolumns img創建一個新的descendant selector。 .no-csscolumns img { margin: 3px 8px 3px 0; float: left; } .columns img規則。兩個規則有著相同的特殊性,因此,如果它們順序顛倒,則.columns img的10像素的左邊距可能會覆蓋你剛剛創建的新規則。你可以將.no-csscolumns img重命名為.no-csscolumns .columns img以便於給它更高的特殊性,但是最好是保證selector越簡單越好。 (順便說一下,如果你不確定什麼是特殊性,查閱Adrian Senior的文章,Understanding Specificity。它雖然發表時間很長,但是很有價值。) 在這個的簡單範例中,我只用了前綴為no-的類就為舊版本的瀏覽器創建了特殊的樣式。 但是,按照它們的能力,你不同時使用這兩個類(帶或不帶前綴)為瀏覽器創建不同的樣式是絕對沒有道理的。 例如:
.csscolumns { /* rules for browsers that support multi-column layout */ } .no-csscolumns { /* rules for browsers that don't support multi-column layout */ }有時這種方法是合理的,例如,如果你想為每一級支持都創建一個完全不同的佈局。 但是如果它僅僅是一個為舊版本瀏覽器提供可選擇的樣式的問題,不要忘記,瀏覽器會忽略它們無法識別的屬性。 如果你對所有的樣式都使用Modernizr 類,那麼在JavaScript 禁用的瀏覽器中你的頁面將完全非樣式化。
Modernizr 為開始的<html>標籤添加的類名稱起著雙重目的作用。當頁面加載時,它們也是Modernizr 對象創建的JavaScript 屬性的名稱。表1列舉了與CSS 有關的類和屬性的名稱。表2列舉了剩下的與HTML5 和相關技術有關的類和屬性,例如地理位置。
表2. Modernizr 檢測的與HTML5 有關的功能
HTML5 有關功能 | Modernizr 類(屬性) |
Application cache | applicationcache |
Audio | audio. type (ogg, mp3, wav, m4a) |
Canvas | canvas |
Canvas text | canvastext |
Drag and drop | draganddrop |
Form input attributes | input. attributeName |
Form input elements | inputtypes. elementName |
Geolocation | geolocation |
hashchange event | hashchange |
History management | history |
IndexedDB | indexeddb |
Inline SVG | inlinesvg |
Local storage | localstorage |
Messaging | postmessage |
Session storage | sessionstorage |
SMIL | smil |
SVG | svg |
SVG clip paths | svgclippaths |
Touch events | touch |
Video | video. type (ogg, webm, h264) |
WebGL | webgl |
Web sockets | websockets |
Web SQL database | websqldatabase |
Web workers | webworkers |
在大多數情況下,表1和表2列舉的所有屬性返回的都是true或者false 。所以,你可以按照如下所示使用JavaScript 對本地存儲進行測試:
if (Modernizr.localstorage) { // script to run if local storage is supported } else { // script to run if local storage is not supported }然而,就audio和video而言,返回值是一個字符串,它表明著瀏覽器能夠處理特定類型的置信水平。 根據HTML5 規範,空的字符串表示該類型不支持。 如果支持該類型,那麼返回值是maybe或是probably。 例如:
if (Modernizr.video.h264 == ) { // h264 is not supported }HTML5 添加了許多新的表單屬性,例如autofocus ,當頁面第一次加載時它會自動地將光標放在某個指定的字段。 另一個有用的屬性是required , 如果某個必需的字段留有空白,那麼它將阻止HTML5兼容的瀏覽器提交表單(參見圖6)。
這很好,但是它會給你留下一個問題:舊版本的瀏覽器該怎麼辦?
一個解決方法是忽略它們,並留給服務器側的驗證功能進行最終的檢查。 如果瀏覽器無法識別required屬性,那麼另外一個處理這種情況的用戶界面更為友好的方法是創建一個小小的腳本對必需字段進行檢查。 如下的指令顯示了在Modernizr幫助下如何進行相應的操作。
</style> <script src=js/modernizr.js></script> </head> <script>塊,並且在頁面一加載完就創建一個事件處理程序以便於執行代碼:<script src=js/modernizr.js></script> <script> window.onload = function() { // code to execute when page loads }; </script> </head autofocus和required屬性的瀏覽器中模擬它們。處理autofocus的方式很簡單:window.onload = function() { // get the form and its input elements var form = document.forms[0], inputs = form.elements; // if no autofocus, put the focus in the first field if (!Modernizr.input.autofocus) { inputs[0].focus(); } // if required not supported, emulate it }該條件測試了Modernizr.input.autofocus ,如果不支持autofocus ,那麼返回的值是false 。 然而,邏輯運算符NOT(一個感嘆號)卻能使意思顛倒,因此如果不支持autofocus ,那麼該條件的求值結果為true ,並且inputs[0].focus()將光標放在第一個輸入字段。
required ,那麼現在添加代碼以便於檢查必需字段。 事件處理程序的完整代碼如下所示:window.onload = function() { // get the form and its input elements var form = document.forms[0], inputs = form.elements; // if no autofocus, put the focus in the first field if (!Modernizr.input.autofocus) { inputs[0].focus(); } // if required not supported, emulate it if (!Modernizr.input.required) { form.onsubmit = function() { var required = [], att, val; // loop through input elements looking for required for (var i = 0; i < inputs.length; i++) { att = inputs[i].getAttribute('required'); // if required, get the value and trim whitespace if (att != null) { val = inputs[i].value; // if the value is empty, add to required array if (val.replace(/^/s+|/s+$/g, '') == '') { required.push(inputs[i].name); } } } // show alert if required array contains any elements if (required.length > 0) { alert('The following fields are required: ' + required.join(', ')); // prevent the form from being submitted return false; } }; } }新代碼產生了一個函數,當提交表單時它能夠遍歷所有的輸入元素,以便於找到具有required屬性的字段。 當它找到某個字段時,它會從值中除去開頭和結尾的空白,並且如果結果是一個空的字符串,那麼它會把結果添加到required數組中。 在所有的字段都已經得到檢查後,如果數組中包含某些元素,那麼瀏覽器會顯示一個與缺失字段名稱有關的警告,並阻止提交表單。
注意: Safari 5.1 錯誤地報告了它支持required屬性,所以它在沒有驗證必需字段的情況下就提交了表單。 這是Safari 的缺陷,然而在Modernizr 裡它是不存在的。
當你準備好對你的網站進行部署時,推薦創建一個Modernizr 的自定義production 版本,它只包含那些你實際需要的元素。 這可以按照你所選的功能將Modernizr 庫的大小從44KB 縮小到2KB。當前選項的範圍如圖8所示。
圖8. Modernizr 下載頁面允許你僅選擇那些你需要的功能選項可以便捷地按照如下類別進行分組:CSS3、HTML5、Misc(ellaneous) 和Extra。 單擊前三個標題旁邊的Toggle 按鈕可任意地選擇或者放棄選擇分類中的所有復選框。
在默認情形下,Extra 分類將會選中如下三個條目:
如果你在CSS3 分類中選中任何選項,那麼如下Extra 分類中的選項也會被選中:
Modernizr.testProp() Modernizr.testAllProps() Modernizr._domPrefixes()不要取消選擇這些選項。 這樣做將會自動地取消你在CSS3 分類中已經選擇的任何選項。
Extra 分類中的MQ Polyfill (respond.js) 添加了一個腳本,它可以使IE 6-8中的media queries 獲得有限的支持。當你選中這個選項時,它會自動地選中Media Queries 和Modernizr.testStyles()。如需知道更多關於media queries polyfill (respond.js)的信息,請訪問https://github.com/scottjehl/Respond。
只有高級用戶才會對Extra 分類中的其它選項感興趣。關於它們是什麼和如何使用它們的更多細節,參見Modernizr 文檔的擴展性部分(Extensibility section of the Modernizr documentation)。
下面的說明描述瞭如何為範例文件創建一個Modernizr 的自定義production版本。 後續的練習需要使用這一自定義版本,它將展示如何使用Modernizr.load()加載外部JavaScript 文件。
當創建Modernizr的自定義production版本時,在默認情形下,必須選中包含Modernizr.load()的選項。 Modernizr.load()是yepnope()的別名,它是與Modernizr 同步開發的獨立腳本加載器。 為了說明如何使用它,我給出一個簡單範例。我已經將相應的腳本從required.html 移到了check_required.js,並且做了三個微小的改動以便於去除Modernizr 測試以及將它賦值到一個名為init的變量中。 修訂的腳本如下所示:
var init = function() { // get the form and its input elements var form = document.forms[0], inputs = form.elements; // put the focus in the first input field inputs[0].focus(); // check required fields when the form is submitted form.onsubmit = function() { var required = [], att, val; // loop through input elements looking for required for (var i = 0; i < inputs.length; i++) { att = inputs[i].getAttribute('required'); // if required, get the value and trim whitespace if (att != null) { val = inputs[i].value; // if the value is empty, add to required array if (val.replace(/^/s+|/s+$/g, '') == '') { required.push(inputs[i].name); } } } // show alert if required array contains any elements if (required.length > 0) { alert('The following fields are required: ' + required.join(', ')); // prevent the form from being submitted return false; } }; }; Modernizr.load()的一個很大的優點是,根據測試瀏覽器能力的結果,它可以有條件地加載腳本—這就是為什麼起初叫它yepnope()的原因。 它可以異步地加載外部腳本—換句話說,就是能夠在瀏覽器已加載Document Object Model (DOM) 之後加載外部腳本—因此它可以有助於提升你的網站性能。
Modernizr.load()的基本語法是將一個具有如下屬性的對像傳遞給它:
test : 你希望檢測的Modernizr 屬性。 yep : 如果測試成功,你希望加載的腳本的位置。 使用一個多腳本數組。 nope : 如果測試失敗,你希望加載的腳本的位置。 使用一個多腳本數組。 complete : 外部腳本一經加載就運行的函數(可選)。 yep和nope兩者都是可選的,只要你提供了其中一個即可。
為了在check_required.js 中加載和執行腳本,需要在modernizr.adc.js 已附著到頁面之後添加如下<script>塊(代碼位於required_load.html 中):
<script> Modernizr.load({ test: Modernizr.input.required, nope: 'js/check_required.js', complete: function() { init(); } }); </script>這樣就與之前運行的完全一致,但是卻可以降低已支持required屬性的瀏覽器的下載負荷。
為了測試多種條件,你可以給Modernizr.load()傳遞一組對象。如需獲得更多細節信息,參見Modernizr 文檔上的Modernizr.load() 教程。
Modernizr 是一個強大而有用的工具,但是這並不意味著你就應該使用它。 並不是在所有情形下均必須使用Modernizr 給瀏覽器提供多種樣式。 如果你主要關注的對像是Internet Explorer,那麼考慮使用IE conditional comments。 你也可以使用CSS層疊覆蓋一些樣式。 例如,先使用hexadecimal color,然後使用rgba()或hsla()覆蓋它。 舊版本的瀏覽器會使用第一個值並且忽略第二個值。
Modernizr 真正地變成現實是當它與polyfills 和其它JavaScript 相結合的時候。但是記住,通常很容易創建屬於你自己的適合支持功能的測試。例如,下面就是你測試某個瀏覽器是否支持required屬性的全部代碼(代碼位於required_nomodernizr.html 中):
var elem = document.createElement('input'); if (typeof elem.required != 'boolean') { // required is not supported }本教程已經涵蓋了Modernizr 的所有主要功能如需了解關於這些功能的更多信息,請查閱相應的官方文檔,其網站地址為http://www.modernizr.com/docs/。 此外,你還可以找到下列有用資源:
yepnope()的深入討論,它已經在Modernizr 中被合併為Modernizr.load() 。 +