JavaScript >> Javascript 文檔 >  >> JavaScript

今天使用 HTML5 語義元素

在過去的一年中,關於是否使用新的 HTML5 語義元素的爭論已經演變為如何 使用新的 HTML5 語義元素。所有主要瀏覽器都在今年年底之前(許多在本季度末之前)正式支持這些元素,因此,現在是開始使用這些新元素的時候了。當然,世界不僅僅是由支持 HTML5 的瀏覽器組成的,因此為向後兼容而編寫的問題是許多人試圖回答的主要問題。

問題

使用新語義元素的最大問題是不支持的瀏覽器如何處理它們。在頁面中使用 HTML5 元素時,基本上有三種可能的結果:

  1. 標籤被視為錯誤並被完全忽略。 DOM 的構造就像標籤不存在一樣。
  2. 標籤被認為是一個錯誤,並創建一個 DOM 節點作為佔位符。 DOM 的構造如代碼所示,但標籤未應用任何樣式(視為內聯元素)。
  3. 標籤被識別為 HTML5 標籤,並創建一個 DOM 節點來表示它。 DOM 的構造如代碼所示,並且標記應用了適當的樣式(在許多情況下,作為塊元素)。

作為一個具體的例子,考慮這個代碼:

<div class="outer">
    <section>
        <h1>title</h1>
        <p>text</p>
    </section>
</div>

許多瀏覽器(例如​​ Firefox 3.6 和 Safari 4)會將其解析為頂級 <div> 具有未知子元素的元素 (<section> ) 在 DOM 中創建但被視為內聯元素。 <h1><p> 元素是 <section> 的子元素 .因為 <section> 在 DOM 中表示,可以設置元素的樣式。這是案例 #2。

9 之前的 Internet Explorer 將其解析為頂級 <div> 但看到 <section> 作為一個錯誤。所以 <section> 被忽略,然後 <h1><p> 被解析,都成為 <div> 的孩子 .結束 </section> 也被視為錯誤並被跳過。在瀏覽器中有效理解這段代碼相當於:

<div class="outer">
    <h1>title</h1>
    <p>text</p>
</div>

因此,較舊的 Internet Explorer 瀏覽器實際上可以很好地從未知元素中恢復,但創建的 DOM 結構與其他瀏覽器不同。因為未知元素沒​​有 DOM 表示,所以您也不能將樣式應用於 <section> .這是案例#1。

當然,支持 HTML5 的瀏覽器(例如​​ Internet Explorer 9、Firefox 4 和 Safari 5)會創建正確的 DOM 結構,並且還會將正確的默認樣式應用於 HTML5 中指定的元素。

所以最大的問題是,瀏覽器不僅為相同的代碼生成不同的 DOM 結構,而且為相同的 DOM 結構生成不同的樣式規則。

解決方案

今天,許多人提出了許多不同的解決方案來在頁面中使用 HTML5 元素。每次都嘗試解決已經提到的一個或多個特定問題,以提供跨瀏覽器兼容性。

JavaScript 墊片

JavaScript 填充程序旨在主要解決舊 Internet Explorer 瀏覽器中 HTML5 元素樣式的問題。 Internet Explorer 中有一個眾所周知的怪癖,它無法識別未知元素,除非這些元素之一已經通過 document.createElement() 創建 .因此瀏覽器將創建一個 DOM 元素並允許設置 <section> 的樣式 元素只要 document.createElement("section") 被調用。

諸如 html5shim 1 之類的墊片 使用此功能可確保 HTML5 元素在 Internet Explorer 中正確創建 DOM 元素,從而允許您應用樣式。 Shims 通常還將 HTML5 塊元素設置為 display: block 所以它們在其他瀏覽器中也能正確顯示。

我不喜歡這種方法,因為它違反了我的主要 Web 應用程序原則之一:不應依賴 JavaScript 進行佈局。這不僅僅是為那些禁用 JavaScript 的人創造一個糟糕的體驗,它是關於製作一個可預測和可維護的 Web 應用程序代碼庫,其中層之間有明確的關注點分離。它確實具有在所有瀏覽器中生成相同 DOM 結構的好處,從而確保您的 JavaScript 和 CSS 在任何地方都完全相同,但在我看來,這種好處並沒有超過缺點。

命名空間破解

從不缺少黑客攻擊,Internet Explorer 還有另一種使瀏覽器識別未知元素的技術。這首先通過 Elco Klingen 的文章獲得廣泛關注,HTML5 elements in Internet Explorer without JavaScript 2 .該技術涉及聲明一個 XML 樣式的命名空間,然後使用帶有命名空間前綴的元素,例如:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html5="http://www.w3.org/html5/">
<body>
    <html5:section>
        <!-- content -->
    </html5:section>
</body>
</html>

html5 前綴只是純粹的假裝,根本不是官方的——你也可以讓前綴是“foo”,效果是一樣的。有了前綴,Internet Explorer 將識別新元素,以便您可以應用樣式。這也適用於其他瀏覽器,因此您最終會得到相同的 DOM 和相同的樣式。

缺點很明顯:您必須在 HTML 文檔中使用 XML 樣式的命名空間,並在 CSS 中使用它們,意思是這樣的:

html5\:section {
    display: block;
}

這不是我希望 Web 開發人員編寫代碼的方式。這是解決問題的絕妙解決方案,但它教會了我認為是新元素的不自然應用。我不想看到充滿命名空間元素的文件。

“防彈”技術

我第一次接觸到這項技術是在 YUIConf 2010 上,當時 Tantek Çelik 發表了題為 HTML5:Right Here, Right Now 的演講 3 .在那次演講中,Tantek 建議使用內部 <div> 每個新的 HTML5 塊元素的元素,並在該 <div> 上包含 CSS 類名稱 表示它代表 HTML5 元素。例如:

<section><div class="section">
   <!-- content -->
</div></section>

這種方法的目的是確保內容在所有瀏覽器中正確流動。在應該是塊的 HTML5 元素內使用一個塊元素意味著您將擁有一個塊元素(Internet Explorer <9),一個內聯元素(Firefox 3.6、Safari 4 等)內的塊元素,或塊元素內的塊元素(Internet Explorer 9、Firefox 4、Safari 5 等)。在這三種情況下,默認渲染都是一樣的。

Tantek 確實注意到了一個不起作用的例外情況,那就是 <hgroup> ,它明確禁止非標題子元素。為此,他建議將 <div> 在外面:

<div class="hgroup"><hgroup>
   <!-- content -->
</hgroup></div>

對於樣式,Tantek 建議不要嘗試設置 HTML5 元素本身的樣式,而是設置代理 <div> 的樣式 .所以不要這樣:

section {
    color: blue;
}

使用這個:

.section {
    color: blue;
}

理由是以後很容易自動將此模式轉換為引用 HTML5 元素標記名稱的模式。我不喜歡他的這部分建議,因為我通常不喜歡通過標籤名稱應用樣式。

這種方法的缺點是不同的瀏覽器會創建不同的 DOM 結構,因此在編寫 JavaScript 和 CSS 時必須小心。例如,使用直接子選擇器(> ) 跨 HTML5 元素不會在所有瀏覽器中工作。另外,直接訪問 parentNode 可能會導致不同瀏覽器中的不同節點。這在如下代碼中尤為明顯:

<div class="outer">
    <section><div class="section main">
        <!-- content -->
    </div></section>
</div>

如果您有一個選擇器,例如 section > .main ,它不會在 Internet Explorer 8 和更早版本中應用。每當您跨越 HTML 4 到 HTML5 到 HTML 4 的障礙時,就會遇到這些問題。

反向防彈技術

還有其他帖子,例如 Thierry Koblentz 的,HTML 元素和代理 DIV 4 已經探索了反轉 Tantek 的方法,以便 HTML5 元素出現在 <div> 內 元素。例如:

<div class="section"><section>
    <!-- content -->
</section><div>

唯一的區別是 HTML5 元素的位置——其他一切都是一樣的。支持者喜歡這種技術是因為它的一致性(對所有元素都一樣,包括 <hgroup> )。值得注意的是,作為選擇器使用和 JavaScript DOM 遍歷的一部分,這種方法與 Tantek 有相同的警告。它的主要優點是技術的一致性。

我的方法

我選擇一種方法的主要目標是確保我只需要對頁面的 HTML 進行更改。這意味著對 CSS 或 JavaScript 的更改為零。為什麼提出這樣的要求?必須更改的 Web 應用程序(或任何應用程序)的層數越多,您引入錯誤的可能性就越大。將更改限制在一層會限制錯誤的引入,如果發生錯誤,則會將您對潛在問題的搜索限制在一個區域。例如,如果佈局中斷,我會知道這是因為我添加了 <section> 而不是將其與更改該區域樣式的 CSS 相結合。

在研究了這些技術,做了一些原型設計和測試之後,我最終回到了 Tantek 的方法。它是唯一一個我可以在不需要更改 CSS 和 JavaScript 的情況下讓我正在製作原型的所有現有頁面工作的地方。現在,我沒有按照他寫信的方式,做了一些我認為可以改進的地方。

首先,我從來沒有根據代表 HTML5 元素的類名來設置任何樣式(所以沒有 .section 在我的選擇器中)。我保持相同的 <div> 已經在頁面中的元素並使用應用於這些元素的語義類名稱作為我的樣式和 JavaScript 鉤子。比如這段代碼:

<div class="content">
    <!-- content -->
</div>

變成了這個代碼:

<section><div class="section content">
    <!-- content -->
</div></section>

有了這個更改,我仍然使用 .content 作為頁面該區域的樣式和腳本鉤子。這樣做,我已經擁有的 JavaScript 和 CSS 不需要更改。

其次,不要有 <hgroup> 的特殊情況 ,我選擇不使用它。誠實的事實是,我在現有的任何頁面中都找不到該元素有用的任何地方。自 <hgroup> 只能包含標題,包含 <hgroup> 最安全 如果你真的想的話,可以單獨使用(假設它包含在另一個塊元素中)。

我確實花了相當多的時間在防彈和反向防彈之間來回彈跳,試圖確定哪一個效果最好。對我來說,關鍵的決定因素是反向防彈需要我添加 CSS 才能使其工作。在為 HTML5 元素創建 DOM 節點但未應用默認樣式的瀏覽器中,在 <div> 內有 HTML5 塊元素 不止一次弄亂了我的佈局,因為它們在舊版瀏覽器中變成了內聯元素。我必須顯式添加規則以使它們成為塊元素以使我的佈局正常工作,這打破了我自己不更改 CSS 以使事情正常工作的要求。

證明

在這個討論領域,我發現令人難以置信的令人沮喪的一件事是,人們過快地放棄一種方法,因為他們至少可以找到一種不起作用的情況。我在這裡提出的解決方案都不是完美的。它們都不適用於您可能遇到的每種情況。如果你給我任何技術,我幾乎可以向你保證,有人可以想出一個不起作用的情況。這不會使該技術無效,它只是通知您該技術的局限性,以便您做出更好的決定。

在我的研究中,我使用了幾個現有的頁面並將它們轉換為使用修改後的防彈技術。我將它們放在具有簡單佈局和復雜佈局的頁面中,有和沒有 JavaScript 交互的頁面中。在每種情況下,我所做的唯一更改是對 HTML 的更改,並且一切都繼續正常工作(對 JavaScript 或 CSS 沒有更改)。那些關於子節點和父節點關係的警告呢?有趣的是我從來沒有遇到過這些問題。

當然,這對我來說可能如此簡單的原因是因為我對編碼的嚴格要求。我虔誠地再次檢查:

  • 標籤名稱和 ID 未用於應用樣式(僅使用類名稱)
  • CSS 選擇器盡可能通用並使用盡可能少的選擇器類型
  • JavaScript 不依賴特定的 DOM 結構來工作
  • 標籤名稱未用於操作 DOM

我注意到的另一件有趣的事情是我使用 HTML5 元素作為容器。這些新元素實際上只是功能組之間的界限,而不是其他任何東西。您大部分時間都在這些邊界內對項目進行樣式設置和腳本編寫,而不是自己跨越邊界。由於我的 JavaScript 和 CSS 以容器內部發生的事情為目標,一切都繼續工作。 我懷疑大多數編碼良好的網站都會出現這種情況。

結論

我最終決定並向其他人推薦的技術是對 Tantek 防彈技術的修改。顯然這個名字有點用詞不當,因為 CSS 和 JavaScript 有一些副作用,但在我的實驗中,它確實似乎是一種允許我只更改頁面的 HTML 並讓一切繼續工作的方法.我相信這場辯論將在公司內部和整個互聯網上繼續進行,我希望這篇文章能幫助你做出明智的決定。

參考

  1. html5shim
  2. 沒有 JavaScript 的 Internet Explorer 中的 HTML5 元素 , by Elco Klingen
  3. HTML5:就在此時此地 , Tantek Çelik(視頻、幻燈片)
  4. HTML 元素和代理 DIV , 蒂埃里·科布倫茨(Thierry Koblentz)

Tutorial JavaScript 教程
  1. 如何構建隨機報價生成器。

  2. 如何使用 Next.js 生成動態站點地圖

  3. 防止 TypeScript 公共函數調用私有函數

  4. 在 html 文本框中設置鍵盤插入符號位置

  5. 審查某人的代碼! - OSD600 - 實驗室 01

  6. 如何調試電子應用程序

  7. 如何檢測圖像加載失敗,如果失敗,嘗試重新加載直到成功?

  1. Hapi on Steroids – 將生成器函數與 Hapi 一起使用

  2. 如何構建運行良好的 Vue 組件

  3. 使用 React Hooks 構建鋼琴

  4. 插件反應中 webpack 錯誤的簡單修復發生衝突...

  5. 🌀 Typescript 中的 Mixins 🍀

  6. 使調試器工作

  7. 棄用通知:React 18 不再支持 ReactDOM.render

  1. 如何製作滑塊(旋轉木馬)

  2. 默認 parseInt 基數為 10

  3. 使其可訪問:Angular 中不再有文字牆

  4. Heroku H10-App崩潰錯誤的原因及解決方法