1. 程式人生 > 實用技巧 >前端編碼風格規範之 HTML 規範

前端編碼風格規範之 HTML 規範

HTML 規範


文件型別

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

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

HTML 中最好不要將無內容元素[1]的標籤閉合,例如:使用<br>而非<br />.


HTML 驗證

一般情況下,建議使用能通過標準規範驗證的 HTML 程式碼,除非在效能優化和控制檔案大小上不得不做出讓步。

使用諸如 W3C HTML validator 這樣的工具來進行檢測。

規範化的 HTML 是顯現技術要求與侷限的顯著質量基線,它促進了 HTML 被更好地運用。

不推薦

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

推薦

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

省略可選標籤

HTML5 規範中規定了 HTML 標籤是可以省略的。但從可讀性來說,在開發的原始檔中最好不要這樣做,因為省略標籤可能會導致一些問題。

省略一些可選的標籤確實使得頁面大小減少,這很有用,尤其是對於一些大型網站來說。為了達到這一目的,我們可以在開發後期對頁面進行壓縮處理,在這個環節中這些可選的標籤完全就可以省略掉了。


指令碼載入

出於效能考慮,指令碼非同步載入很關鍵。一段指令碼放置在<head>內,比如<script src="main.js"></script>,其載入會一直阻塞 DOM 解析,直至它完全地載入和執行完畢。這會造成頁面顯示的延遲。特別是一些重量級的指令碼,對使用者體驗來說那真是一個巨大的影響。

非同步載入指令碼可緩解這種效能影響。如果只需相容 IE10+,可將 HTML5 的 async 屬性加至指令碼中,它可防止阻塞 DOM 的解析,甚至你可以將指令碼引用寫在<head>

裡也沒有影響。

如需相容老舊的瀏覽器,實踐表明可使用用來動態注入指令碼的指令碼載入器。你可以考慮yepnopelabjs。注入指令碼的一個問題是:一直要等到 CSS 物件文件已就緒,它們才開始載入(短暫地在 CSS 載入完畢之後),這就對需要及時觸發的 JS 造成了一定的延遲,這多多少少也影響了使用者體驗吧。

終上所述,相容老舊瀏覽器(IE9-)時,應該遵循以下最佳實踐。

指令碼引用寫在 body 結束標籤之前,並帶上 async 屬性。這雖然在老舊瀏覽器中不會非同步載入指令碼,但它只阻塞了 body 結束標籤之前的 DOM 解析,這就大大降低了其阻塞影響。而在現代瀏覽器中,指令碼將在 DOM 解析器發現 body 尾部的 script 標籤才進行載入,此時載入屬於非同步載入,不會阻塞 CSSOM(但其執行仍發生在 CSSOM 之後)。

所有瀏覽器中,推薦

<html>
  <head>
    <link rel="stylesheet" href="main.css">
  </head>
  <body>
    <!-- body goes here -->

    <script src="main.js" async></script>
  </body>
</html>

只在現代瀏覽器中,推薦

<html>
  <head>
    <link rel="stylesheet" href="main.css">
    <script src="main.js" async></script>
  </head>
  <body>
    <!-- body goes here -->
  </body>
</html>

語義化

根據元素(有時被錯誤地稱作“標籤”)其被創造出來時的初始意義來使用它。打個比方,用 heading 元素來定義頭部標題,p 元素來定義文欄位落,用 a 元素來定義連結錨點,等等。

有根據有目的地使用 HTML 元素,對於可訪問性、程式碼重用、程式碼效率來說意義重大。

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

不推薦

<b>My page title</b>
<div class="top-navigation">
  <div class="nav-item"><a href="#home">Home</a></div>
  <div class="nav-item"><a href="#news">News</a></div>
  <div class="nav-item"><a href="#about">About</a></div>
</div>

<div class="news-page">
  <div class="page-section news">
    <div class="title">All news articles</div>
    <div class="news-article">
      <h2>Bad article</h2>
      <div class="intro">Introduction sub-title</div>
      <div class="content">This is a very bad example for HTML semantics</div>
      <div class="article-side-notes">I think I'm more on the side and should not receive the main credits</div>
      <div class="article-foot-notes">
        This article was created by David <div class="time">2014-01-01 00:00</div>
      </div>
    </div>

    <div class="section-footer">
      Related sections: Events, Public holidays
    </div>
  </div>
</div>

<div class="page-footer">
  Copyright 2014
</div>

推薦

<!-- The page header should go into a header element -->
<header>
  <!-- As this title belongs to the page structure it's a heading and h1 should be used -->
  <h1>My page title</h1>
</header>

<!-- All navigation should go into a nav element -->
<nav class="top-navigation">
  <!-- A listing of elements should always go to UL (OL for ordered listings) -->
  <ul>
    <li class="nav-item"><a href="#home">Home</a></li>
    <li class="nav-item"><a href="#news">News</a></li>
    <li class="nav-item"><a href="#about">About</a></li>
  </ul>
</nav>

<!-- The main part of the page should go into a main element (also use role="main" for accessibility) -->
<main class="news-page" role="main">
  <!-- A section of a page should go into a section element. Divide a page into sections with semantic elements. -->
  <section class="page-section news">
    <!-- A section header should go into a section element -->
    <header>
      <!-- As a page section belongs to the page structure heading elements should be used (in this case h2) -->
      <h2 class="title">All news articles</h2>
    </header>

    <!-- If a section / module can be seen as an article (news article, blog entry, products teaser, any other
     re-usable module / section that can occur multiple times on a page) a article element should be used -->
    <article class="news-article">
      <!-- An article can contain a header that contains the summary / introduction information of the article -->
      <header>
        <!-- As a article title does not belong to the overall page structure there should not be any heading tag! -->
        <div class="article-title">Good article</div>
        <!-- Small can optionally be used to reduce importance -->
        <small class="intro">Introduction sub-title</small>
      </header>

      <!-- For the main content in a section or article there is no semantic element -->
      <div class="content">
        <p>This is a good example for HTML semantics</p>
      </div>
      <!-- For content that is represented as side note or less important information in a given context use aside -->
      <aside class="article-side-notes">
        <p>I think I'm more on the side and should not receive the main credits</p>
      </aside>
      <!-- Articles can also contain footers. If you have footnotes for an article place them into a footer element -->
      <footer class="article-foot-notes">
        <!-- The time element can be used to annotate a timestamp. Use the datetime attribute to specify ISO time
         while the actual text in the time element can also be more human readable / relative -->
        <p>This article was created by David <time datetime="2014-01-01 00:00" class="time">1 month ago</time></p>
      </footer>
    </article>

    <!-- In a section, footnotes or similar information can also go into a footer element -->
    <footer class="section-footer">
      <p>Related sections: Events, Public holidays</p>
    </footer>
  </section>
</main>

<!-- Your page footer should go into a global footer element -->
<footer class="page-footer">
  Copyright 2014
</footer>

多媒體回溯

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

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

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

不推薦

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

推薦

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

儘量用 alt 標籤去描述圖片,設想你需要對於那些只能通過語音或者看不見圖片的使用者表達圖片到底是什麼。

不推薦

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

推薦

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

關注點分離

理解 web 中如何和為何區分不同的關注點,這很重要。這裡的關注點主要指的是:資訊(HTML 結構)、外觀(CSS)和行為(JavaScript)。為了使它們成為可維護的乾淨整潔的程式碼,我們要儘可能的將它們分離開來。

嚴格地保證結構、表現、行為三者分離,並儘量使三者之間沒有太多的互動和聯絡。

就是說,儘量在文件和模板中只包含結構性的 HTML;而將所有表現程式碼,移入樣式表中;將所有動作行為,移入指令碼之中。

在此之外,為使得它們之間的聯絡儘可能的小,在文件和模板中也儘量少地引入樣式和指令碼檔案。

清晰的分層意味著:

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

不推薦

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="base.css">
  <link rel="stylesheet" href="grid.css">
  <link rel="stylesheet" href="type.css">
  <link rel="stylesheet" href="modules/teaser.css">
</head>
<body>
  <h1 style="font-size: 3rem"></h1>
  <b>I'm a subtitle and I'm bold!</b>
  <center>Dare you center me!</center>
  <script>
    alert('Just dont...');
  </script>
  <div class="red">I'm important!</div>
</body>
</html>

推薦

<!DOCTYPE html>
<html>
<head>
  <!-- Concatinate your style sheets into a single one -->
  <link rel="stylesheet" href="main.css">
</head>
<body>
  <!-- Don't use style attributes but assign sensible classes and apply styles in the stylesheet -->
  <h1 class="title"></h1>
  <!-- Don't use presentational elements and assign sensible classes -->
  <div class="sub-title">I'm a subtitle and I'm bold!</div>
  <!-- Maybe your comments get centered in your presentation but that decision is up to the stylesheet -->
  <span class="comment">Dare you center me!</span>
  <!-- You wanted to make it red because it's important so then also name the class important and decide in the stylesheet
   what you want to do with it -->
  <div class="important">I'm important!</div>

  <!-- Put all your scripts into files and concatinate them into a single one -->
  <script async src="main.js"></script>
</body>
</html>

HTML 內容至上

不要讓非內容資訊汙染了你的 HTML。現在貌似有一種傾向:通過 HTML 來解決設計問題,這是顯然是不對的。HTML 就應該只關注內容。

HTML 標籤的目的,就是為了不斷地展示內容資訊。

  • 不要引入一些特定的 HTML 結構來解決一些視覺設計問題
  • 不要將img元素當做專門用來做視覺設計的元素

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

不推薦

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

推薦

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

圖片和 SVG 圖形能被引入到 HTML 中的唯一理由是它們呈現出了與內容相關的一些資訊。

不推薦

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

推薦

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

Type 屬性

省略樣式表與指令碼上的 type 屬性。鑑於 HTML5 中以上兩者預設的 type 值就是 text/css 和 text/javascript,所以 type 屬性一般是可以忽略掉的。甚至在老舊版本的瀏覽器中這麼做也是安全可靠的。

不推薦

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

推薦

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

可用性

如果 HTML5 語義化標籤使用得當,許多可用性問題已經引刃而解。ARIA 規則在一些語義化的元素上可為其添上預設的可用性角色屬性,使用得當的話已使網站的可用性大部分成立。假如你使用nav,aside,main,footer等元素,ARIA 規則會在其上應用一些關聯的預設值。 更多細節可參考ARIA specification

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


Tab Index 在可用性上的運用

檢查文件中的 tab 切換順序並傳值給元素上的 tabindex,這可以依據元素的重要性來重新排列其 tab 切換順序。你可以設定tabindex="-1"在任何元素上來禁用其 tab 切換。

當你在一個預設不可聚焦的元素上增加了功能,你應該總是為其加上tabindex屬性使其變為可聚焦狀態,而且這也會啟用其 CSS 的偽類:focus。選擇合適的tabindex值,或是直接使用tabindex="0"將元素們組織成同一 tab 順序水平,並強制干預其自然閱讀順序。


微格式在 SEO 和可用性上的運用

如果 SEO 和可用性環境條件允許的話,建議考慮採用微格式。微格式是通過在元素標籤上申明一系列特定資料來達成特定語義的方法。

谷歌、微軟和雅虎對如何使用這些額外的資料一定程度上的達成一致,如果正確的使用,這將給搜尋引擎優化帶來巨大的好處。

你可以訪問schema.org獲得更多內容細節。

看一個電影網站的簡單例子:

不帶微格式

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

帶有微格式

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

ID 和錨點

通常一個比較好的做法是將頁面內所有的頭部標題元素都加上 ID. 這樣做,頁面 URL 的 hash 中帶上對應的 ID 名稱,即形成描點,方便跳轉至對應元素所處位置。

打個比方,當你在瀏覽器中輸入 URLhttp://your-site.com/about#best-practices,瀏覽器將定位至以下 H3 上。

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

格式化規則

在每一個塊狀元素,列表元素和表格元素後,加上一新空白行,並對其子孫元素進行縮排。內聯元素寫在一行內,塊狀元素還有列表和表格要另起一行。

(如果由於換行的空格引發了不可預計的問題,那將所有元素併入一行也是可以接受的,格式警告總好過錯誤警告)。

推薦

<blockquote>
  <p><em>Space</em>, the final frontier.</p>
</blockquote>

<ul>
  <li>Moe</li>
  <li>Larry</li>
  <li>Curly</li>
</ul>

<table>
  <thead>
    <tr>
      <th scope="col">Income</th>
      <th scope="col">Taxes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$ 5.00</td>
      <td>$ 4.50</td>
    </tr>
  </tbody>
</table>

HTML 引號

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

不推薦

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

推薦

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

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