讀書小組的網頁需要的不只是依次排好的文字。標題應識別這一頁,導覽應帶領讀者到適當的位置,時間表則應保留每個活動與開始時間之間的關係。HTML 把這些關係寫進文件,讓瀏覽器及其他工具能理解內容的組織方式。
第一步是準確描述內容。其後加入外觀及互動功能時,便能沿用同一個清晰結構。本單元從一份小型文件出發,區分原始文字、元素、屬性,以及瀏覽器建立的文件結構。
標記描述內容的角色
HTML 是 **Hypertext Markup Language(超文字標記語言)**的縮寫。瀏覽器解讀標記,從而建立文件。當頁面需要變數、條件分支及事件處理邏輯時,JavaScript 便提供這些行為,而 HTML 結構仍是這些行為所作用的基礎。
定義
元素、標籤與屬性
HTML 元素代表文件的一部分,例如段落、標題或連結。標籤在原始碼中標示元素的範圍。屬性提供元素的額外資料,寫在開始標籤內。
<a href="week2.html" class="reading-link">第二次閱讀討論</a>
這裏的 a 是元素名稱,<a ...> 是開始標籤,</a> 是結束標籤。兩者之間的文字是連結標籤。href 屬性指定目的地;class 則指派一個可重用的名稱,供 CSS 或 JavaScript 選取。類別名稱本身不會產生視覺效果。
大部分元素能包含文字或其他合適的元素。巢狀關係表達內容的包含關係:
<p>討論前請閱讀<strong>首兩節</strong>。</p>
strong 元素位於段落內,表示內容的重要性。瀏覽器可能把它顯示成粗體,但它表達的意思比字體選擇更具體。em 表示語氣上的強調。b、i 和 u 也有各自的文字語義;只因預設外觀合用而選擇元素,便容易混淆意思與呈現方式。純粹的外觀要求應交由 CSS 處理。
有些元素是空元素,例如 img、br、meta 和 link。它們沒有結束標籤,也不能包含子內容。有語義需要的換行可寫成 <br>。段落仍應使用 p;連續加入換行並不會建立段落結構。
在 HTML 語法中,一般 HTML 標籤名稱不區分大小寫。使用小寫名稱、為屬性值加引號,以及一致地縮排,會令原始碼更容易檢查。縮排協助人閱讀巢狀關係;真正決定結構的是標籤。
文件把中繼資料與主要內容分開
例題
一份完整的小型讀書小組文件
把以下文字儲存為 index.html,再用瀏覽器開啟。這是一份完整文件,沒有腳本或外部樣式表。
<!doctype html>
<html lang="zh-Hant">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>讀書小組:活動安排</title>
</head>
<body>
<header>
<h1>讀書小組</h1>
<p>每週討論一篇短篇技術文章。</p>
</header>
<nav aria-label="本頁導覽">
<a href="#schedule">活動安排</a>
<a href="#preparation">事前準備</a>
</nav>
<main>
<section id="schedule">
<h2>活動安排</h2>
<p>下一次討論於 16:00 開始。</p>
</section>
<section id="preparation">
<h2>事前準備</h2>
<p>帶來一條關於閱讀內容的問題。</p>
</section>
</main>
<footer>
<p>由讀書小組籌辦。</p>
</footer>
</body>
</html>
<!doctype html> 宣告選用標準 HTML 文件模式。html 是文件的根元素,其 lang 值識別主要語言。語言資料有助工具選用合適的發音及文字處理方式。
head 包含文件的中繼資料。charset 宣告字元編碼;UTF-8 能表示本課筆記使用的中英文。title 在瀏覽器分頁及其他情境中識別文件。視窗宣告要求流動裝置瀏覽器以裝置寬度作為排版視窗寬度,並以比例 1 開始顯示。
body 包含頁面的文件內容,當中的 h1 是內容的一部分。因此 title 與 h1 的角色互相關聯,但並不相同:更改分頁標題,不會自動更改頁面內的標題。
中繼資料亦可以指向樣式表、腳本或圖示。帶有 rel="stylesheet" 的 link 元素指向樣式表;帶有 href 的 a 元素則建立可供導覽的超連結。兩者都使用 URL,並不表示兩種元素可以互換。
註解使用 <!-- ... -->。註解可以解釋原始碼,而不成為頁面上呈現的文字。讀者檢視原始碼時仍能看到註解。
按意思選擇結構
首個例子使用語義元素,標明各區域的角色:
| 元素 | 在讀書小組頁面中的角色 |
|---|---|
header | 頁面的介紹內容 |
nav | 一組主要導覽連結 |
main | 文件的主要主題內容 |
section | 一組具有共同主題的內容,通常由標題引入 |
aside | 與周邊主要內容相關、但屬旁支的資料 |
footer | 關於頁面或所屬章節的資料 |
以一個可見的 main 表達頁面主要內容。頁面可以有自己的頁首,某一節亦可以有自己的 header;周邊結構決定它介紹哪一部分。若沒有更具體的語義角色,則可用 div 作一般分組。
h1 至 h6 表達不同組織層級。例子中的 h1 命名整頁,h2 命名各個主要章節。「事前準備」之下的分節可使用 h3。只因 h4 看起來較小而選用它,會令層級關係變得含糊;應先選對標題層級,再用樣式調整大小。
id 識別文件中的一個元素。每個 ID 應保持唯一,令片段連結有明確目的地。class 可以由多個元素共用,用來表示共同的樣式或腳本分類。ID 和類別都不會取代承載它們的元素本身的語義。
思考檢查
文件的哪一部分會改變?
假設瀏覽器分頁顯示「讀書小組:活動安排」,頁面內的標題則是「讀書小組」。現在要把可見標題改成「秋季讀書小組」,應修改哪個元素?現有 ID 是否也需要更改?
解答 · 標題與識別名稱
修改 h1 內的文字。瀏覽器分頁標題由 title 控制。更改標題文字不要求更改元素的 id;ID 識別目的地,與讀者看到的文字互相獨立。例子中的 h1 沒有 ID,這次修改也不需要新增一個。
超連結連接文件與位置
帶有 href 的錨點元素代表超連結。連結文字應描述目的地,因為讀者可能在沒有周邊段落的情況下接觸該文字。
<a href="week2.html">第二次閱讀討論</a>
<a href="#schedule">跳至活動安排</a>
URL 可以是絕對網址,例如 https://example.test/club/week2.html,也可以是相對於文件基底 URL 的網址。在沒有 base 元素改變基底的情況下,相對 URL 會以文件 URL 為基礎解析。路徑是否以 / 開頭,會影響解析結果。
例題
從目前文件解析連結
假設文件 URL 是 https://example.test/club/reading/index.html。
href | 解析後的目的地 |
|---|---|
week2.html | https://example.test/club/reading/week2.html |
../index.html | https://example.test/club/index.html |
/help.html | https://example.test/help.html |
#schedule | 目前文件中的 schedule 片段 |
第一個路徑從目前目錄出發。第二個先返回上一層目錄。第三個以斜線開頭,因此從來源網站的根目錄出發。第四個保留同一份文件,並指定其中一個位置;前面的 id="schedule" 就提供了這個目的地。
target 屬性選擇導覽發生的位置。_self 使用目前的瀏覽情境,也是一般預設值。_blank 要求建立新的瀏覽情境,瀏覽器通常會以新分頁呈現。它不會改變目的地 URL。
片段目的地必須與預期元素的 ID 相符。在這個例子中,若連結寫成 href="#Schedule",元素卻是 id="schedule",便不是所需的精確配對。
清單與表格表達不同關係
項目只形成一組集合、沒有有意義的先後次序時,使用無序清單。當次序是內容的一部分,例如準備步驟時,使用有序清單。
<h2>事前準備</h2>
<ol>
<li>閱讀文章。</li>
<li>寫下一條問題。</li>
<li>選一段文字作討論。</li>
</ol>
每個 li 是一個清單項目。有序清單可以使用 start="5" 由 5 開始編號,或以 type="A" 使用字母標記。內容仍應具有順序。裝飾性的標記形狀通常屬於 CSS 的工作。
表格表達橫列與直欄之間的關係。活動時間表適合用表格,因為每一列把一個主題與開始時間配對。若只是要把互不相關的頁面區域排成數欄,就不應以表格代替版面配置。
例題
明確標示表頭的時間表
<table>
<caption>讀書小組活動</caption>
<thead>
<tr>
<th scope="col">主題</th>
<th scope="col">開始時間</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">HTML 結構</th>
<td>16:00</td>
</tr>
<tr>
<th scope="row">超連結</th>
<td>16:30</td>
</tr>
</tbody>
</table>
tr 建立一列,th 識別表頭儲存格,td 則容納資料儲存格。scope="col" 把頂部表頭與相應直欄關聯;scope="row" 表示主題是該橫列的表頭。caption 描述整個表格。即使改變表格外觀,這些關係仍然有用。
圖像需要資源,也需要角色
img 元素以 src 指向圖像資源。alt 提供圖像的文字替代內容。撰寫時,應先問這幅圖像在目前情境中傳達甚麼資料。
<img src="images/reading-room.jpg"
width="640" height="360"
alt="一間閱讀室,六個座位圍着一張共用桌子">
若圖像提供資訊,便描述其中相關的資訊。若圖像純粹用作裝飾,沒有需要傳達的額外資訊,可以使用 alt=""。width 與 height 描述圖像尺寸,亦協助瀏覽器在載入資源前確立長寬比例。試用這段程式碼時,應把圖像放在文件旁邊的 images 目錄內。
點陣圖像以像素網格表示內容。SVG 則以形狀與座標表示向量圖形。簡單的示意圖可以直接用內嵌 SVG 描述幾何結構:
<svg viewBox="0 0 120 60" role="img" aria-labelledby="circle-title">
<title id="circle-title">讀書小組的圓形徽章</title>
<circle cx="60" cy="30" r="18" fill="currentColor"></circle>
</svg>
圓心在 SVG 座標系中的 (60, 30),半徑是 18。viewBox 定義座標矩形。這幅圖形透過 aria-labelledby,使用 title 取得名稱。
picture 元素提供多個圖像資源選項。它包含若干 source,最後接一個 img;後者提供文字替代內容及預設資源:
<picture>
<source media="(min-width: 48rem)" srcset="images/room-wide.jpg">
<img src="images/room-close.jpg" width="640" height="360"
alt="閱讀室內的共用桌子">
</picture>
當媒體條件成立時,瀏覽器可選擇較闊的構圖;否則仍可使用預設圖像。picture 容器本身不會取代 img 元素。
文字字元與空白受解析規則影響
某些字元在 HTML 語法中有特定用途。字元參照讓原始碼把這些字元表達成文字,而不是標記語法:
| 原始文字 | 所代表的字元 |
|---|---|
< | 小於號 |
> | 大於號 |
& | 與號 |
" | 雙引號 |
| 不斷行空格 |
使用包含分號的完整形式。例如原始碼 <p>2 < 5 & 5 < 8</p> 會顯示文字 2 < 5 & 5 < 8。
在一般空白處理方式下,普通段落內連續的空格、換行及定位字元會在顯示時合併。原始碼中把段落縮排若干空格,不表示呈現結果也會縮排同樣距離。不斷行空格可讓 Week 2 這類組合保持在同一行,但不應用來代替版面間距。
pre 在預設樣式下保留空白,適合預先格式化的文字。它不會停用 HTML 解析。若要顯示 HTML 原始碼,應轉義標記字元,並把結果放在 code 內:
<pre><code><h2>活動安排</h2>
<p>帶來一條問題。</p></code></pre>
結果會顯示兩行原始碼,而不是建立標題與段落。sub 與 sup 則表達有相應意義的下標與上標,例如 H<sub>2</sub>O 和 r<sup>2</sup>。
從兩個層次檢查文件
「檢視網頁原始碼」顯示提供給瀏覽器的 HTML 原始內容。瀏覽器開發者工具則顯示目前的文件結構,包括解析過程或 JavaScript 所作的改動。兩者回答不同問題:輸入的原始碼是甚麼,以及現在存在甚麼結構?
當頁面不如預期時,先檢查元素角色與巢狀關係,再檢查目的地屬性、資源路徑和文字內容。瀏覽器可能修復格式不正確的 HTML,因此能看到畫面,並不等於原始碼已表達預期結構。
常見錯誤
預先格式化的區塊仍會解析 HTML
把 <h2>活動安排</h2> 直接放進 pre,會建立元素,而不是印出尖括號。保留空白與解讀字元是兩套不同規則。當預期內容是原始碼時,應使用字元參照。
練習
思考檢查
練習 1:組織一份小型文件
讀書小組網頁有介紹標題、通往兩節的導覽、準備指示,以及籌辦者資料。選擇合適的區域元素及標題層級,並解釋為何不能只因某種標題看起來較小,就決定選用該層級。
解答 · 練習 1 解答
頁面 header 包含 h1;nav 包含主要連結;一個 main 包含兩個按主題組織的 section,每節使用 h2。籌辦者資料放在頁面 footer。標題層級表達組織關係,外觀由 CSS 決定。主要章節之下的分節應使用 h3,即使期望的字體大小與另一層級相近。
思考檢查
練習 2:解析路徑與片段
在 https://example.test/club/reading/index.html,解析 ../archive.html 與 /archive.html。再寫出一個通往 ID 為 questions 的章節連結,並說明 href 與可能加入的 target 屬性有甚麼分別。
解答 · 練習 2 解答
第一個目的地是 https://example.test/club/archive.html;第二個是 https://example.test/archive.html。章節連結可寫成 <a href="#questions">討論問題</a>。href 識別目的地;target,例如 _self 或 _blank,則選擇導覽使用的瀏覽情境。
思考檢查
練習 3:解讀一個表格儲存格
在前面的時間表中,為何「16:30」使用 td,「超連結」卻使用帶有 scope="row" 的 th?頂部的「開始時間」表頭又提供甚麼資料?
解答 · 練習 3 解答
「16:30」是某次活動的開始時間資料。「超連結」識別該橫列所代表的活動,因此是橫列表頭。「開始時間」直欄表頭則指出這些時間值的意思。兩個表頭合起來,把儲存格解讀為「超連結」活動的開始時間。
思考檢查
練習 4:顯示原始碼文字
寫出 HTML,在預先格式化的程式碼區塊中顯示字面文字 <p>2 < 5</p>。然後解釋為何在普通段落加入空格,不能可靠地把時間表各欄對齊。
解答 · 練習 4 解答
<pre><code><p>2 < 5</p></code></pre>
字元參照把尖括號變成文字的一部分,pre 則保留程式碼的空白。在普通段落中,重複空格會被合併,而空格的視覺寬度亦受字體影響。時間表具有橫列與直欄的關係,應由表格直接表達其結構。
要把文件結構與伺服器提供的資源連起來,可回看瀏覽器、伺服器與網頁資源。