
內容摘要
瀏覽器會默默修好壞掉的 HTML,所以頁面看起來正常、標記卻是錯的。真正不能省的是 doctype、lang、charset、viewport 與 title。
HTML 是一門寬容的語言,而這正是標記錯誤能存活下來的原因:瀏覽器會默默修好你寫的東西,於是頁面看起來正常,文件卻不是你想的那個樣子。這篇講一份文件真正需要的結構、哪些部分可選但重要,以及那些幾週後才變成版面問題的錯誤。
文中每個範例都可以在 UrsaKit 的 HTML 網上工具 上試,它會邊打字邊在沙箱預覽中渲染你的標記。
01瀏覽器很寬容,這才是問題
把沒關閉的 <div>、儲存格對不上的表格,或巢狀在段落裡的段落丟給瀏覽器,它不會報錯——它會猜。HTML 解析算法之所以被規定得如此詳細,正是因為這些猜測必須在每個瀏覽器上一致。
實際的缺點是:你拿到的 DOM 不一定是你寫的 DOM。<p> 裡再放 <p> 會讓第一個段落提前結束,<table> 裡的 <div> 會被移到表格外面,<ul> 裡不合法的巢狀會變成文字節點。
唯一可靠的方式是檢查渲染後的 DOM,而不是原始檔。每個瀏覽器的開發者工具都能看到解析後的樹。
02每份文件都需要的五行
<!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>
<h1>一個標題,說明這個頁面</h1>
</body>
</html>
每一行都有它在你拿掉之前看不見的作用:
<!doctype html>讓瀏覽器離開 quirks mode。少了它,盒模型、百分比高度與行高都會走舊規則。lang告訴屏幕閱讀器該用哪種發音,也讓瀏覽器正確斷字。請填真實的語言標籤,例如zh-Hant或es。charset必須放在 head 的第一位。放錯位置或寫錯,所有非 ASCII 字元都會變成亂碼。viewport是頁面對流動裝置友善的關鍵;少了它,手機會以模擬的 980 像素寬度渲染。title是分頁、書籤與搜尋結果上的標籤。
一個頁面只留一個 h1。
h1 是這個頁面的主題。如果每一區都用 h1 開頭,搜尋引擎與屏幕閱讀器用戶都無法判斷頁面在講什麼。區段用 h2,區段裡的小節用 h3。
03head 與 body 的分工
head 放的是關於文件的資訊,body 放的是用戶看到的內容。把兩者混在一起,是困惑最常見的來源之一。
| 屬於 head | 屬於 body |
|---|---|
title、meta、link | h1–h6、p、ul |
整頁適用的 style | 用戶會閱讀或點擊的元素 |
加上 defer 的 script | 放在 body 結尾的 script |
| favicon 與 preload 提示 | template 與 noscript 備援 |
放在 head 的內容不會被渲染;該放 head 卻寫在 body 的標記會被搬移或忽略。如果某個樣式表連結看起來完全沒作用,先確認它是不是跑進 body 了。
04空元素與跳脫
有些元素沒有內容、也沒有結束標籤,稱為空元素。寫出 </img> 是解析錯誤,只是瀏覽器願意忍受。
<img src="/logo.png" alt="UrsaKit 標誌" width="1161" height="389" />
<input type="email" name="email" required />
<br />
<hr />
<meta charset="utf-8" />
兩條規則就涵蓋了大多數跳脫錯誤:
- & 會開始一個實體。 想顯示字面上的
&就寫&,否則&可能被當成字元引用的開頭而改變文字。 - 屬性裡的引號。 屬性值用雙引號包起來,內部的雙引號寫成
",或把該屬性改用單引號。
圖片一定要同時設定 width 與 height。瀏覽器會在檔案下載完成前先保留空間,避免版面位移破壞閱讀位置與 Core Web Vitals。
05語意元素到底改變了什麼
section、article、nav 與 div 渲染出來都是沒有預設樣式的區塊。選哪一個不影響畫素,所以很多團隊乾脆全部用 div。但這個交換是有代價的:
- 屏幕閱讀器只能在標記有定義地標時,才能在地標之間跳轉。
- 爬蟲靠標題與地標判斷頁面的主要內容在哪裡。
- 你自己的 CSS 與測試會得到
nav ul這種選擇器,而不是.wrapper-3 ul。
| 元素 | 用在哪 |
|---|---|
header / footer | 頁面或區段的開頭與結尾內容 |
nav | 一組導覽連結 |
main | 唯一的內容主體,每頁一次 |
article | 單獨拿出來也說得通的內容 |
section | 有自己標題的主題群組 |
div | 只是為了樣式而存在的容器 |
06七個值得修掉的標記錯誤
| 錯誤 | 實際發生什麼 | 修正 |
|---|---|---|
| 沒有 doctype | Quirks mode 改變盒模型與高度規則 | 加上 <!doctype html> |
lang 缺少或錯誤 | 發音與斷字都不正確 | 填真實的語言標籤 |
| charset 不在 head 第一位 | 非 ASCII 文字變亂碼 | 把 meta charset 放最前面 |
<table> 裡放 <div> | div 被移到表格外 | 用 thead、tbody、tr、td |
p 裡放區塊元素 | 段落提前結束 | 先關段落,再開區塊 |
head 裡的 script 沒加 defer | 解析要等下載並執行完 | 加上 defer 或移到結尾 |
id 重複 | getElementById 與 label 只會抓到第一個 | 保持 id 唯一 |
07不用建置流程就能測標記
- 貼上完整文件或片段 — HTML 工具 兩者都收。片段會自動包成最小文件,方便單獨檢查一個元件。
- 邊打字邊看預覽 — 預覽在沙箱框架中渲染,腳本可以執行,卻不會碰到工具本身的頁面。
- 比對 DOM,而不是你的原始碼 — 看起來不對時,直接在預覽裡檢查元素。瀏覽器會修標記,只有解析後的樹能告訴你真正建出了什麼。
- 接著處理樣式 — 結構對了之後,把同一份標記帶進 CSS 網上編輯器 調版面,或在 JavaScript 網上執行器 上跑行為。
從一開始就把結構寫對,比事後發現某個版面 bug 其實是 HTML bug 便宜得多。
寫完標記立刻在沙箱預覽中看到渲染結果,不需要任何建置流程。
HTML 網上工具常見問題
還需要寫 doctype 嗎?
要。少了它,瀏覽器會進入 quirks mode,盒模型與行高改用舊規則,版面會以很難追查的方式壞掉。
html、head、body 可以省略嗎?
瀏覽器會自己補上,但請明確寫出來。隱含的元素在原始碼裡看不見,除錯比多打四個標籤更慢。
lang 屬性會改變什麼?
它告訴屏幕閱讀器該用哪種語言發音、讓瀏覽器正確斷字與引用,也幫助搜尋引擎判斷頁面語言。
script 標籤該放哪裡?
放在 head 裡並加上 defer,或放在 body 結尾。直接放在 head 的 script 會在下載與執行完成前阻塞解析。
HTML 可以用自我閉合標籤嗎?
對 img、br 這類空元素來說,結尾斜線會被忽略,所以 img src="x" / 合法但沒有意義;加在非空元素上則是解析錯誤。
語意化標記會改變外觀嗎?
不會。section、article 與 div 渲染結果完全相同。語意改變的是輔助科技與爬蟲理解到的內容,也讓 CSS 與 JavaScript 有更明確的掛鉤。
相關文章
- 用 CSS 把 div 置中
同一張頁面的排版另一半。
- 做出每次都能掃到的 QR 碼
當標記與打印尺寸不一致時會發生什麼事。
相關工具
- HTML 網上工具
在沙箱預覽中渲染標記。
- CSS 網上編輯器
即時為同一份標記加上樣式。
- JavaScript 網上執行器
對你建立的頁面執行腳本。
- 正則表達式測試器
找出需要修改的標記位置。