前端編碼規(guī)范(2)—— HTML 規(guī)范

2015-01-30 10:55:50來源:WEB前端開發(fā)作者:

這是一份旨在增強(qiáng)團(tuán)隊(duì)的開發(fā)協(xié)作,提高代碼質(zhì)量和打造開發(fā)基石的編碼風(fēng)格規(guī)范,其中包含了 HTML, JavaScript 和 CSS/SCSS 這幾個(gè)部分。

HTML 規(guī)范


文檔類型

推薦使用 HTML5 的文檔類型申明: <!DOCTYPE html>.

(建議使用 text/html 格式的 HTML。避免使用 XHTML。XHTML 以及它的屬性,比如 application/xhtml+xml 在瀏覽器中的應(yīng)用支持與優(yōu)化空間都十分有限)。

HTML 中最好不要將無內(nèi)容元素[1] 的標(biāo)簽閉合,例如:使用 <br> 而非 <br />.


HTML 驗(yàn)證

一般情況下,建議使用能通過標(biāo)準(zhǔn)規(guī)范驗(yàn)證的 HTML 代碼,除非在性能優(yōu)化和控制文件大小上不得不做出讓步。

使用諸如 W3C HTML validator 這樣的工具來進(jìn)行檢測。

規(guī)范化的 HTML 是顯現(xiàn)技術(shù)要求與局限的顯著質(zhì)量基線,它促進(jìn)了 HTML 被更好地運(yùn)用。

不推薦

  1. <title>Test</title>
  2. <article>This is only a test.

推薦

  1. <!DOCTYPE html>
  2. <meta charset="utf-8">
  3. <title>Test</title>
  4. <article>This is only a test.</article>

省略可選標(biāo)簽

HTML5 規(guī)范中規(guī)定了 HTML 標(biāo)簽是可以省略的。但從可讀性來說,在開發(fā)的源文件中最好不要這樣做,因?yàn)槭÷詷?biāo)簽可能會導(dǎo)致一些問題。

省略一些可選的標(biāo)簽確實(shí)使得頁面大小減少,這很有用,尤其是對于一些大型網(wǎng)站來說。為了達(dá)到這一目的,我們可以在開發(fā)后期對頁面進(jìn)行壓縮處理,在這個(gè)環(huán)節(jié)中這些可選的標(biāo)簽完全就可以省略掉了。


腳本加載

出于性能考慮,腳本異步加載很關(guān)鍵。一段腳本放置在 <head> 內(nèi),比如 <script src="main.js"></script>,其加載會一直阻塞 DOM 解析,直至它完全地加載和執(zhí)行完畢。這會造成頁面顯示的延遲。特別是一些重量級的腳本,對用戶體驗(yàn)來說那真是一個(gè)巨大的影響。

異步加載腳本可緩解這種性能影響。如果只需兼容 IE10+,可將 HTML5 的 async 屬性加至腳本中,它可防止阻塞 DOM 的解析,甚至你可以將腳本引用寫在 <head> 里也沒有影響。

如需兼容老舊的瀏覽器,實(shí)踐表明可使用用來動態(tài)注入腳本的腳本加載器。你可以考慮 yepnope 或labjs。注入腳本的一個(gè)問題是:一直要等到 CSS 對象文檔已就緒,它們才開始加載(短暫地在 CSS 加載完畢之后),這就對需要及時(shí)觸發(fā)的 JS 造成了一定的延遲,這多多少少也影響了用戶體驗(yàn)吧。

終上所述,兼容老舊瀏覽器(IE9-)時(shí),應(yīng)該遵循以下最佳實(shí)踐。

腳本引用寫在 body 結(jié)束標(biāo)簽之前,并帶上 async 屬性。這雖然在老舊瀏覽器中不會異步加載腳本,但它只阻塞了 body 結(jié)束標(biāo)簽之前的 DOM 解析,這就大大降低了其阻塞影響。而在現(xiàn)代瀏覽器中,腳本將在 DOM 解析器發(fā)現(xiàn) body 尾部的 script 標(biāo)簽才進(jìn)行加載,此時(shí)加載屬于異步加載,不會阻塞 CSSOM(但其執(zhí)行仍發(fā)生在 CSSOM 之后)。

所有瀏覽器中,推薦

  1. <html>
  2. <head>
  3. <link rel="stylesheet" href="main.css">
  4. </head>
  5. <body>
  6. <!-- body goes here -->
  7.  
  8. <script src="main.js" async></script>
  9. </body>
  10. </html>

只在現(xiàn)代瀏覽器中,推薦

  1. <html>
  2. <head>
  3. <link rel="stylesheet" href="main.css">
  4. <script src="main.js" async></script>
  5. </head>
  6. <body>
  7. <!-- body goes here -->
  8. </body>
  9. </html>

語義化

根據(jù)元素(有時(shí)被錯(cuò)誤地稱作“標(biāo)簽”)其被創(chuàng)造出來時(shí)的初始意義來使用它。打個(gè)比方,用 heading 元素來定義頭部標(biāo)題,p 元素來定義文字段落,用 a 元素來定義鏈接錨點(diǎn),等等。

有根據(jù)有目的地使用 HTML 元素,對于可訪問性、代碼重用、代碼效率來說意義重大。

以下示例列出了一些的語義化 HTML 主要情況:

不推薦

  1. <b>My page title</b>
  2. <div class="top-navigation">
  3. <div class="nav-item"><a href="#home">Home</a></div>
  4. <div class="nav-item"><a href="#news">News</a></div>
  5. <div class="nav-item"><a href="#about">About</a></div>
  6. </div>
  7.  
  8. <div class="news-page">
  9. <div class="page-section news">
  10. <div class="title">All news articles</div>
  11. <div class="news-article">
  12. <h2>Bad article</h2>
  13. <div class="intro">Introduction sub-title</div>
  14. <div class="content">This is a very bad example for HTML semantics</div>
  15. <div class="article-side-notes">I think I'm more on the side and should not receive the main credits</div>
  16. <div class="article-foot-notes">
  17. This article was created by David <div class="time">2014-01-01 00:00</div>
  18. </div>
  19. </div>
  20.  
  21. <div class="section-footer">
  22. Related sections: Events, Public holidays
  23. </div>
  24. </div>
  25. </div>
  26.  
  27. <div class="page-footer">
  28. Copyright 2014
  29. </div>

推薦

  1. <!-- The page header should go into a header element -->
  2. <header>
  3. <!-- As this title belongs to the page structure it's a heading and h1 should be used -->
  4. <h1>My page title</h1>
  5. </header>
  6.  
  7. <!-- All navigation should go into a nav element -->
  8. <nav class="top-navigation">
  9. <!-- A listing of elements should always go to UL (OL for ordered listings) -->
  10. <ul>
  11. <li class="nav-item"><a href="#home">Home</a></li>
  12. <li class="nav-item"><a href="#news">News</a></li>
  13. <li class="nav-item"><a href="#about">About</a></li>
  14. </ul>
  15. </nav>
  16.  
  17. <!-- The main part of the page should go into a main element (also use role="main" for accessibility) -->
  18. <main class="news-page" role="main">
  19. <!-- A section of a page should go into a section element. Divide a page into sections with semantic elements. -->
  20. <section class="page-section news">
  21. <!-- A section header should go into a section element -->
  22. <header>
  23. <!-- As a page section belongs to the page structure heading elements should be used (in this case h2) -->
  24. <h2 class="title">All news articles</h2>
  25. </header>
  26.  
  27. <!-- If a section / module can be seen as an article (news article, blog entry, products teaser, any other
  28. re-usable module / section that can occur multiple times on a page) a article element should be used -->
  29. <article class="news-article">
  30. <!-- An article can contain a header that contains the summary / introduction information of the article -->
  31. <header>
  32. <!-- As a article title does not belong to the overall page structure there should not be any heading tag! -->
  33. <div class="article-title">Good article</div>
  34. <!-- Small can optionally be used to reduce importance -->
  35. <small class="intro">Introduction sub-title</small>
  36. </header>
  37.  
  38. <!-- For the main content in a section or article there is no semantic element -->
  39. <div class="content">
  40. <p>This is a good example for HTML semantics</p>
  41. </div>
  42. <!-- For content that is represented as side note or less important information in a given context use aside -->
  43. <aside class="article-side-notes">
  44. <p>I think I'm more on the side and should not receive the main credits</p>
  45. </aside>
  46. <!-- Articles can also contain footers. If you have footnotes for an article place them into a footer element -->
  47. <footer class="article-foot-notes">
  48. <!-- The time element can be used to annotate a timestamp. Use the datetime attribute to specify ISO time
  49. while the actual text in the time element can also be more human readable / relative -->
  50. <p>This article was created by David <time datetime="2014-01-01 00:00" class="time">1 month ago</time></p>
  51. </footer>
  52. </article>
  53.  
  54. <!-- In a section, footnotes or similar information can also go into a footer element -->
  55. <footer class="section-footer">
  56. <p>Related sections: Events, Public holidays</p>
  57. </footer>
  58. </section>
  59. </main>
  60.  
  61. <!-- Your page footer should go into a global footer element -->
  62. <footer class="page-footer">
  63. Copyright 2014
  64. </footer>

多媒體回溯

對頁面上的媒體而言,像圖片、視頻、canvas 動畫等,要確保其有可替代的接入接口。圖片文件我們可采用有意義的備選文本(alt),視頻和音頻文件我們可以為其加上說明文字或字幕。

提供可替代內(nèi)容對可用性來說十分重要。試想,一位盲人用戶如何能知曉一張圖片是什么,要是沒有 @alt 的話。

(圖片的 alt 屬性是可不填寫內(nèi)容的,純裝飾性的圖片就可用這么做:alt="")。

不推薦

  1. <img src="luke-skywalker.jpg">

推薦

  1. <img src="luke-skywalker.jpg" alt="Luke skywalker riding an alien horse">

盡量用 alt 標(biāo)簽去描述圖片,設(shè)想你需要對于那些只能通過語音或者看不見圖片的用戶表達(dá)圖片到底是什么。

不推薦

  1. <img src="huge-spaceship-approaching-earth.jpg" alt="Header image">

推薦

  1. <img src="huge-spaceship-approaching-earth.jpg" alt="A huge spaceship that is approaching the earth">

關(guān)注點(diǎn)分離

理解 web 中如何和為何區(qū)分不同的關(guān)注點(diǎn),這很重要。這里的關(guān)注點(diǎn)主要指的是:信息(HTML 結(jié)構(gòu))、外觀(CSS)和行為(JavaScript)。為了使它們成為可維護(hù)的干凈整潔的代碼,我們要盡可能的將它們分離開來。

嚴(yán)格地保證結(jié)構(gòu)、表現(xiàn)、行為三者分離,并盡量使三者之間沒有太多的交互和聯(lián)系。

就是說,盡量在文檔和模板中只包含結(jié)構(gòu)性的 HTML;而將所有表現(xiàn)代碼,移入樣式表中;將所有動作行為,移入腳本之中。

在此之外,為使得它們之間的聯(lián)系盡可能的小,在文檔和模板中也盡量少地引入樣式和腳本文件。

清晰的分層意味著:

  • 不使用超過一到兩張樣式表(i.e. main.css, vendor.css)
  • 不使用超過一到兩個(gè)腳本(學(xué)會用合并腳本)
  • 不使用行內(nèi)樣式(<style>.no-good {}</style>)
  • 不在元素上使用 style 屬性(<hr style="border-top: 5px solid black">)
  • 不使用行內(nèi)腳本(<script>alert('no good')</script>)
  • 不使用表象元素(i.e. <b>, <u>, <center>, <font>, <b>)
  • 不使用表象 class 名(i.e. red, left, center)

不推薦

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <link rel="stylesheet" href="base.css">
  5. <link rel="stylesheet" href="grid.css">
  6. <link rel="stylesheet" href="type.css">
  7. <link rel="stylesheet" href="modules/teaser.css">
  8. </head>
  9. <body>
  10. <h1 style="font-size: 3rem"></h1>
  11. <b>I'm a subtitle and I'm bold!</b>
  12. <center>Dare you center me!</center>
  13. <script>
  14. alert('Just dont...');
  15. </script>
  16. <div class="red">I'm important!</div>
  17. </body>
  18. </html>

推薦

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <!-- Concatinate your style sheets into a single one -->
  5. <link rel="stylesheet" href="main.css">
  6. </head>
  7. <body>
  8. <!-- Don't use style attributes but assign sensible classes and apply styles in the stylesheet -->
  9. <h1 class="title"></h1>
  10. <!-- Don't use presentational elements and assign sensible classes -->
  11. <div class="sub-title">I'm a subtitle and I'm bold!</div>
  12. <!-- Maybe your comments get centered in your presentation but that decision is up to the stylesheet -->
  13. <span class="comment">Dare you center me!</span>
  14. <!-- You wanted to make it red because it's important so then also name the class important and decide in the stylesheet
  15. what you want to do with it -->
  16. <div class="important">I'm important!</div>
  17.  
  18. <!-- Put all your scripts into files and concatinate them into a single one -->
  19. <script async src="main.js"></script>
  20. </body>
  21. </html>

HTML 內(nèi)容至上

不要讓非內(nèi)容信息污染了你的 HTML,F(xiàn)在貌似有一種傾向:通過 HTML 來解決設(shè)計(jì)問題,這是顯然是不對的。HTML 就應(yīng)該只關(guān)注內(nèi)容。

HTML 標(biāo)簽的目的,就是為了不斷地展示內(nèi)容信息。

  • 不要引入一些特定的 HTML 結(jié)構(gòu)來解決一些視覺設(shè)計(jì)問題
  • 不要將 img 元素當(dāng)做專門用來做視覺設(shè)計(jì)的元素

以下例子展示了誤將 HTML 用來解決設(shè)計(jì)問題的這兩種情況:

不推薦

  1. <!-- We should not introduce an additional element just to solve a design problem -->
  2. <span class="text-box">
  3. <span class="square"></span>
  4. See the square next to me?
  5. </span>
  1. .text-box > .square {
  2. display: inline-block;
  3. width: 1rem;
  4. height: 1rem;
  5. background-color: red;
  6. }

推薦

  1. <!-- That's clean markup! -->
  2. <span class="text-box">
  3. See the square next to me?
  4. </span>
  1. /* We use a :before pseudo element to solve the design problem of placing a colored square in front of the text content */
  2. .text-box:before {
  3. content: "";
  4. display: inline-block;
  5. width: 1rem;
  6. height: 1rem;
  7. background-color: red;
  8. }

圖片和 SVG 圖形能被引入到 HTML 中的唯一理由是它們呈現(xiàn)出了與內(nèi)容相關(guān)的一些信息。

不推薦

  1. <!-- Content images should never be used for design elements! -->
  2. <span class="text-box">
  3. <img src="square.svg" alt="Square" />
  4. See the square next to me?
  5. </span>

推薦

  1. <!-- That's clean markup! -->
  2. <span class="text-box">
  3. See the square next to me?
  4. </span>
  1. /* We use a :before pseudo element with a background image to solve the problem */
  2. .text-box:before {
  3. content: "";
  4. display: inline-block;
  5. width: 1rem;
  6. height: 1rem;
  7. background: url(square.svg) no-repeat;
  8. background-size: 100%;
  9. }

Type 屬性

省略樣式表與腳本上的 type 屬性。鑒于 HTML5 中以上兩者默認(rèn)的 type 值就是 text/css 和 text/javascript,所以 type 屬性一般是可以忽略掉的。甚至在老舊版本的瀏覽器中這么做也是安全可靠的。

不推薦

  1. <link rel="stylesheet" href="main.css" type="text/css">
  2. <script src="main.js" type="text/javascript"></script>

推薦

  1. <link rel="stylesheet" href="main.css">
  2. <script src="main.js"></script>

可用性

如果 HTML5 語義化標(biāo)簽使用得當(dāng),許多可用性問題已經(jīng)引刃而解。ARIA 規(guī)則在一些語義化的元素上可為其添上默認(rèn)的可用性角色屬性,使用得當(dāng)?shù)脑捯咽咕W(wǎng)站的可用性大部分成立。假如你使用 nav,aside, main, footer 等元素,ARIA 規(guī)則會在其上應(yīng)用一些關(guān)聯(lián)的默認(rèn)值。
更多細(xì)節(jié)可參考 ARIA specification

另外一些角色屬性則能夠用來呈現(xiàn)更多可用性情景(i.e. role="tab")。


Tab Index 在可用性上的運(yùn)用

檢查文檔中的 tab 切換順序并傳值給元素上的 tabindex,這可以依據(jù)元素的重要性來重新排列其 tab 切換順序。你可以設(shè)置 tabindex="-1" 在任何元素上來禁用其 tab 切換。

當(dāng)你在一個(gè)默認(rèn)不可聚焦的元素上增加了功能,你應(yīng)該總是為其加上 tabindex 屬性使其變?yōu)榭删劢範(fàn)顟B(tài),而且這也會激活其 CSS 的偽類 :focus。選擇合適的 tabindex 值,或是直接使用 tabindex="0" 將元素們組織成同一 tab 順序水平,并強(qiáng)制干預(yù)其自然閱讀順序。


微格式在 SEO 和可用性上的運(yùn)用

如果 SEO 和可用性環(huán)境條件允許的話,建議考慮采用微格式。微格式是通過在元素標(biāo)簽上申明一系列特定數(shù)據(jù)來達(dá)成特定語義的方法。

谷歌、微軟和雅虎對如何使用這些額外的數(shù)據(jù)一定程度上的達(dá)成一致,如果正確的使用,這將給搜索引擎優(yōu)化帶來巨大的好處。

你可以訪問 schema.org 獲得更多內(nèi)容細(xì)節(jié)。

看一個(gè)電影網(wǎng)站的簡單例子:

不帶微格式

  1. <div>
  2. <h1>Avatar</h1>
  3. <span>Director: James Cameron (born August 16, 1954)</span>
  4. <span>Science fiction</span>
  5. <a href="../movies/avatar-theatrical-trailer.html">Trailer</a>
  6. </div>

帶有微格式

  1. <div itemscope itemtype ="http://schema.org/Movie">
  2. <h1 itemprop="name">Avatar</h1>
  3. <div itemprop="director" itemscope itemtype="http://schema.org/Person">
  4. Director: <span itemprop="name">James Cameron</span> (born <span itemprop="birthDate">August 16, 1954)</span>
  5. </div>
  6. <span itemprop="genre">Science fiction</span>
  7. <a href="../movies/avatar-theatrical-trailer.html" itemprop="trailer">Trailer</a>
  8. </div>

ID 和錨點(diǎn)

通常一個(gè)比較好的做法是將頁面內(nèi)所有的頭部標(biāo)題元素都加上 ID. 這樣做,頁面 URL 的 hash 中帶上對應(yīng)的 ID 名稱,即形成描點(diǎn),方便跳轉(zhuǎn)至對應(yīng)元素所處位置。

打個(gè)比方,當(dāng)你在瀏覽器中輸入 URL http://your-site.com/about#best-practices,瀏覽器將定位至以下 H3 上。

  1. <h3 id="best-practices">Best practices</h3>

格式化規(guī)則

在每一個(gè)塊狀元素,列表元素和表格元素后,加上一新空白行,并對其子孫元素進(jìn)行縮進(jìn)。內(nèi)聯(lián)元素寫在一行內(nèi),塊狀元素還有列表和表格要另起一行。

(如果由于換行的空格引發(fā)了不可預(yù)計(jì)的問題,那將所有元素并入一行也是可以接受的,格式警告總好過錯(cuò)誤警告)。

推薦

  1. <blockquote>
  2. <p><em>Space</em>, the final frontier.</p>
  3. </blockquote>
  4.  
  5. <ul>
  6. <li>Moe</li>
  7. <li>Larry</li>
  8. <li>Curly</li>
  9. </ul>
  10.  
  11. <table>
  12. <thead>
  13. <tr>
  14. <th scope="col">Income</th>
  15. <th scope="col">Taxes</th>
  16. </tr>
  17. </thead>
  18. <tbody>
  19. <tr>
  20. <td>$ 5.00</td>
  21. <td>$ 4.50</td>
  22. </tr>
  23. </tbody>
  24. </table>

HTML 引號

使用雙引號(“”) 而不是單引號(”) 。

不推薦

  1. <div class='news-article'></div>

推薦

  1. <div class="news-article"></div>

[1]: 此處的空白元素指的是以下元素:area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr

關(guān)鍵詞:前端編碼規(guī)范HTML