
本文將帶你完成以下內容:
- 認識 <dl>/<dt>/<dd> 標籤的語意與結構:為什麼定義清單適合用來做 FAQ?
- 建立 FAQ 頁面的 HTML 架構:使用 <dl>、<dt>、<dd> 組織問答內容。
- 加入 CSS 樣式美化 FAQ 列表:增加問答的可讀性與基本版面配置。
- 加入 JavaScript 讓 FAQ 支持展開/收合互動:點擊問題以展開或收合對應的答案。
- 常見問答單元:解答關於使用 <dl> 製作 FAQ 的常見問題(如為何不用 <ul>、SEO 支援度等)。
接下來,讓我們從基礎開始,一步步實作一個簡單又實用的互動 FAQ 頁面吧!
認識 <dl>/<dt>/<dd>:FAQ 的語意結構
在開始寫程式碼之前,我們先了解 <dl>、<dt>、<dd> 這三個元素代表什麼。<dl> 是 definition list(定義清單)的縮寫,用來呈現「名稱-定義」配對的列表;清單中的每個項目由一個 <dt>(definition term,定義項目)和緊接著的一個 <dd>(definition description,定義描述)組成。傳統上,這組標籤常用於詞彙表或名詞解釋,例如列出專有名詞及其定義。但由於其「名稱對應描述」的語意結構,非常適合拿來表示「問題:答案」這樣的一對一關係,因此我們可以將 FAQ 的每個問答組合用 <dt>/<dd> 來標示,整組問答列表放在一個 <dl> 容器中。
想像 <dl> 就像一本詞典或名詞解釋列表:<dt> 是需要被解釋的詞條,而 <dd> 是對應的解釋說明。應用到 FAQ 上,每個問題就是一個詞條,緊跟在後面的答案就是對該問題的說明。使用 <dl> 來組織 FAQ,可以清楚地表達「這個問題屬於這個答案」的關係。相較之下,如果使用普通段落或清單來列出問答,瀏覽器和開發者就無從直接得知哪一段是問題、哪一段是答案;而使用 <dl> 則在 HTML 結構上就體現了問與答的配對關係,語意更明確。這樣的語意標記對日後的維護或與他人協作也很有幫助——大家一看結構就能理解這是 FAQ 的問答列表。
另外,<dl> 清單在瀏覽器中的預設行為是塊級展示:每個 <dt>、<dd> 會各自佔一行,而 <dd> 會比 <dt> 略微縮進,這剛好符合我們對「問題在前,答案在後且內縮」的視覺預期。了解了這些語意和預設行為後,我們就可以開始動手實作了。
第一步:建立 FAQ 頁面的 HTML 結構
首先,我們來撰寫 FAQ 的 HTML 架構。假設我們要製作一個常見問題列表,包含幾個典型的提問和回答。我們將使用一個 <dl> 元素作為FAQ的容器,在裡面依序放入 <dt>(問題)和 <dd>(答案)元素對。每一對 <dt>...<dd>... 代表一組問答。以下是範例 HTML 結構:
<dl class="faq-list">
<dt>產品是否有保固?</dt>
<dd>我們的產品提供一年保固服務。</dd>
<dt>出貨需要多久?</dt>
<dd>下單後通常可在 3 至 5 個工作天內送達。</dd>
<dt>支援哪些付款方式?</dt>
<dd>我們接受信用卡、轉帳以及行動支付等方式。</dd>
</dl>
在上述結構中,我們做了以下幾件事:
- 用一個 <dl> 將整個 FAQ 區塊包起來,並加上了 class="faq-list"。這個 class 並非必需,但加上後方便我們稍後在 CSS 中針對這個 FAQ 區塊設定樣式(如果頁面上可能有不只一個 <dl>,使用類別名稱來區分也會比較安全)。
- 每個問題用 <dt> 標示,每個答案用 <dd> 標示,而且問題 <dt> 一定緊接著它的答案 <dd> 放置。這很重要,因為 <dl> 依照結構會將 <dt> 與後面的 <dd> 視為一組。如果在兩者中插入其他無關元素,可能會破壞這種配對關係。
- 如此重複建立多組 <dt>...<dd>...,就形成了一系列的問答項目。上述範例中我們示範了三組問答,你可以根據實際需求增減項目的數量。
現在,如果直接在瀏覽器中打開這段 HTML,會看到所有問題和答案依序列出。預設情況下,問題(<dt>)會獨佔一行、答案(<dd>)則會換行並稍微縮排顯示。雖然這已經表達出了問答的層次,但生硬的瀏覽器預設樣式並不好看。接下來,我們會用 CSS 來美化這個 FAQ 列表,讓它更清晰易讀。
提示: 確保每個 <dt> 後面都有對應的 <dd>,不要遺漏或順序顛倒。此外,如果你的頁面上有多個不同主題的 FAQ 區塊,建議為每個 <dl> 添加獨一無二的 class 或 id(例如 class="faq-list product-faq" 等),以方便針對不同區塊設定樣式而不互相干擾。
第二步:加入 CSS 樣式美化 FAQ 列表
有了 HTML 結構之後,我們利用 CSS 來調整 FAQ 列表的外觀。主要目的是區分問題和答案的視覺層次,讓讀者可以輕鬆掃描問題,同時識別出哪段是答案。我們可以對 <dt> 和 <dd> 元素各自設定樣式,例如字體粗細、顏色、縮排和間距等。以下是為 .faq-list FAQ 區塊設定的範例 CSS:
.faq-list {
max-width: 600px; /* 選擇性:限制區塊寬度以改善閱讀體驗 */
margin: 20px auto; /* 選擇性:區塊置中,並上下留白 */
}
.faq-list dt {
font-weight: bold; /* 問題文字加粗 */
color: #333; /* 問題文字顏色較深 */
margin: 0 0 5px; /* 下方留白 5px,與答案保持一點距離 */
}
.faq-list dd {
margin: 0 0 15px 20px; /* 答案縮進 20px,底部留白 15px */
color: #555; /* 答案文字顏色稍淺,區分於問題 */
line-height: 1.6; /* 增加行高,讓答案段落更好讀 */
}
將上面的 CSS 與前一步的 HTML 結合後,我們的 FAQ 列表在外觀上會有明顯提升:
- 問題 (<dt>) 會以粗體深色呈現,吸引讀者目光。每個問題文字與其下方答案之間有一點間距(5px),讓版面更為鬆散不擁擠。
- 答案 (<dd>) 則縮排了一段距離(左側留白 20px),並使用較淡的字體顏色,與問題形成層次差異。同時,我們為答案設定較大的行高(1.6),確保即使答案有多行文字,閱讀起來也不會覺得擁擠。每個答案區塊底部留白 15px,將不同問答組隔開,讓版面更清爽。
應用這些樣式後,FAQ 的版面將更清晰易讀:問題和答案各自分行且樣式區別明顯,讀者可以快速瀏覽問題列表並定位自己關心的問題。此時我們的 FAQ 列表仍然是靜態的(所有答案預設都是展開顯示的)。不過沒關係,下一步我們就要加入 JavaScript 來控制點擊互動,讓答案可以動態地展開或收合。
(當然,你可以根據你的網站風格進一步調整樣式,例如為問題前加上符號、為每組問答加底線分隔等等。以上 CSS 是一個基本範例,重點是確保問題與答案在視覺上易於區分即可。)
第三步:加入 JavaScript 讓 FAQ 支持展開/收合
現在,我們已經有了語意良好的 HTML 結構和美觀的基本樣式。接下來就是讓 FAQ 動起來:當使用者點擊某個問題時,顯示對應的答案;再次點擊時,隱藏該答案。要達成這種展開/收合的互動效果,我們需要做兩件事:
- 隱藏所有答案,等待觸發再顯示: 預設情況下,我們希望頁面載入時所有答案都是收起來的,以避免頁面一下子出現過多資訊。所以我們需要用 CSS 將 <dd> 元素初始狀態設為不顯示。
- 監聽點擊事件並切換顯示狀態: 用 JavaScript 對每一個 <dt>(問題)附加點擊事件監聽器。一旦某個問題被點擊,就切換該問題對應答案的顯示狀態(如果答案原本是隱藏的就展開,原本是顯示的就收起)。
我們先來更新一下 CSS,讓答案預設為隱藏,並為可以點擊的問題添加一些提示樣式:
/* 在前面的CSS基礎上,增加互動所需的樣式 */
.faq-list dt {
cursor: pointer; /* 滑鼠移到問題上時顯示可點擊的指標手勢 */
}
.faq-list dt:hover {
background: #f0f0f0; /* 選擇性:滑鼠懸停時稍微改變背景,提高可點擊感 */
}
.faq-list dd {
display: none; /* 預設隱藏所有答案 */
}
.faq-list dt::after {
content: " +"; /* 在問題後加上「+」符號表示可展開 */
font-weight: bold;
color: #555;
}
.faq-list dt.open::after {
content: " -"; /* 當問題處於展開狀態時,改為顯示「-」符號表示可收合 */
}
.faq-list dt.open + dd {
display: block; /* 當問題有 open 類別時,顯示其對應的答案 */
}
新增的 CSS 部分解釋如下:
- 我們將 .faq-list dd 設定了 display: none,讓頁面載入時所有 <dd> 答案都是隱藏的。這樣使用者剛進入 FAQ 區塊時只會看到問題清單,不會被過多答案文字淹沒。
- 為 .faq-list dt 添加了 cursor: pointer,並設定了 :hover 時略微變色,這些都讓問題看起來更像一個可點擊的按鈕或連結,提示使用者「點我可以有動作發生」。
- 使用 ::after 偽元素在每個問題文字後插入一個「+」符號,表示「點擊展開」。這純粹是視覺上的提示,讓使用者更直觀地知道這些問題是可以展開查看詳細答案的。+ 符號用了 font-weight: bold 和略淺的顏色,以區別於正文,同時不至於喧賓奪主。
- 當問題處於展開狀態時(稍後我們會用 JavaScript 動態為展開的問題添加一個 .open 類別),我們利用 .faq-list dt.open::after 把符號替換成「-」,表示「點擊收合」。這樣使用者一眼就能看出哪幾個問題目前是展開顯示答案的。
- 最後一條 .faq-list dt.open + dd { display: block; } 非常關鍵:它利用了 CSS 相鄰兄弟選擇器,指定「帶有 .open 類別的 <dt> 後面的第一個 <dd>」應該顯示出來。也就是說,當某個問題 <dt> 被標記為展開狀態時(.open),其緊接的答案 <dd> 就會被切換為可見 (display: block)。這條規則配合前面的 dd { display: none; },就實現了顯示/隱藏答案的切換效果。接下來我們透過 JavaScript 來動態控制這個類別的添加和移除。
現在,將下面的 JavaScript 程式碼加入你的頁面(可以放在頁面底部的 <script> 中,或獨立成一個 .js 檔案引用):
<script>
// 取得所有 FAQ 區塊中的問題項目 (<dt>)
const questions = document.querySelectorAll('.faq-list dt');
// 對每個問題項目添加點擊事件監聽
questions.forEach((question) => {
question.addEventListener('click', () => {
// 每次點擊時,切換該問題項目的 "open" 狀態類別
question.classList.toggle('open');
// 說明:
// 如果點擊時 <dt> 沒有 open 類別,toggle 會加上 open 類別(展開答案)
// 如果點擊時已經有 open 類別,toggle 會將它移除(收合答案)
});
});
</script>
上述腳本的運作原理:
- 利用 document.querySelectorAll('.faq-list dt') 選取頁面中所有 FAQ 清單裡的 <dt> 元素(問題)。這會返回一個 NodeList,包含我們FAQ區塊中的每一個 <dt>。
- 使用 forEach 對這個 NodeList 進行迴圈,對每一個問題項目設定一個點擊事件監聽器。
- 當某個 <dt> 被點擊時,觸發我們提供的函式。函式裡呼叫 question.classList.toggle('open'),這一行會在該 <dt> 元素的 class 名單中切換 'open' 這個類別:如果原本沒有 'open' 就添加上去,如果原本有了就移除它。
- 隨著 'open' 類別的添加或移除,我們在 CSS 中設定的規則(.faq-list dt.open + dd { ... } 以及 dt.open::after 等)就會生效或失效。結果就是:點擊後,如果 <dt> 獲得了 .open 類別,它後面的 <dd> 會按照 CSS 規則被顯示出來,同時問題後的符號由 + 變成 -;反之,再次點擊移除 .open 類別,對應的 <dd> 又被隱藏,符號也變回 +。
經過這一步,我們的 FAQ 列表就具備了基本的互動功能!現在打開頁面你應該會看到:所有答案默認是收起隱藏的,每個問題後面有個 + 符號提示可以展開。當你點擊某個問題時,該問題下面會動態顯示出答案內容,問題後的符號從 + 變為 -;當你再次點擊同一問題時,答案會收合隱藏,符號也回復為 +。你可以任意點開多個問題的答案——每個問題的展開/收合是獨立控制的。
提示: 目前我們是用 CSS 直接將答案預設隱藏。如果有些使用者的瀏覽器禁用了 JavaScript,這種做法會導致他們無法看到答案(因為 JS 未執行,自然無法展開隱藏的內容)。為了改善無法執行 JS 時的體驗,你可以考慮改進實作方式:例如不要在 CSS 中預設隱藏 <dd>,而是在頁面加載完畢、JavaScript 執行時才用腳本去隱藏所有答案。如此一來,如果 JS 沒有執行,使用者至少能看到完整的問答內容(只是沒有折疊效果);而如果 JS 正常執行,腳本會隱藏答案並啟用點擊展開功能。另一種方法是利用 <noscript> 標籤提示使用者「請開啟腳本以瀏覽 FAQ 答案」。依照你的需求與使用族群,你可以選擇適合的做法來增強可靠性。
到這裡,我們已成功完成一個基於 <dl> 定義清單的互動 FAQ 頁面實作!你可以在自己的專案中套用這種方式,享受語意清晰的標記方式和輕量級的腳本所帶來的便利。在進一步探討延伸應用之前,我們來看幾個相關的常見問題。
常見問答 (FAQ)
問:為什麼不用 <ul> 或其他列表標籤來做 FAQ?
答: 確實,你可以用無序列表 <ul> 配合 <li> 列出問答,但語意上就沒有那麼清晰了。<ul>/<li> 本質上表示的是並列的項目清單,瀏覽器和開發者無法從結構上直接看出「哪一個問題對應哪一個答案」。通常在 <li> 裡你可能會用 <strong> 包裹問題文字,再接著答案內容,或用其他方式手動區分問答,這樣雖然也能呈現出類似效果,但在 HTML 結構上並未明確表達問答的配對關係。相較之下,使用 <dl>/<dt>/<dd> 則天生就是一對名稱-描述的配對結構:我們的每個 <dt> 問題後面跟著 <dd> 答案,這對關係在標記上清清楚楚。這不僅對我們自己維護代碼更直觀,對未來接手的開發者也更友善——一 glance 就能懂這是一組FAQ的問答。此外,在無障礙方面,某些螢幕閱讀器會將 <dl> 宣告為「定義列表」,並在朗讀時提醒這是一系列術語及其定義的組合,等於會把問題當作術語、答案當作定義來逐對朗讀,讓視障使用者更容易理解問答關係;而用 <ul> 列表則無法提供這種語意上的輔助提示。總而言之,使用 <dl> 來做 FAQ 可以讓結構和語意更加清晰嚴謹,這也是良好前端開發習慣的一部分。
問:使用 <dl> 製作 FAQ 這種方式對 SEO 友好嗎?搜尋引擎會識別這樣的問答結構嗎?
答: 從純 SEO 角度而言,使用 <dl> 標籤本身不會特別強化或削弱你的搜尋排名。搜索引擎主要關心的是內容的品質,以及你是否有提供結構化資料等。FAQ 的文字內容不論包在 <dl> 裡還是 <ul> 或其他標籤裡,搜尋引擎的爬蟲都能讀取索引,因為它們最終看到的只是頁面文本資訊。所以放心,用 <dl> 寫 FAQ 不會對一般的SEO造成負面影響。而在某些情況下,語意良好的 HTML 還有助於搜尋引擎更好地解析頁面內容結構,至少不會產生誤解。需要注意的是,如果你希望在 Google 的搜尋結果中出現那種帶有展開問答的富摘要(FAQ Rich Results),僅靠 HTML 結構還不夠,你還需要加入結構化資料(Schema Markup),比如使用 FAQPage 的 JSON-LD 標記每個問答。這部分跟你用 <dl> 或 <ul> 撰寫FAQ無關,而是 SEO 優化的額外步驟。簡而言之:使用 <dl> 來製作 FAQ 頁面沒有任何SEO上的壞處,可以安心使用;只是不會因為用了 <dl> 就自動獲得特殊的搜尋加成。如果想讓 FAQ 在搜尋結果中脫穎而出,記得考慮搭配結構化資料來實現。
問:為什麼不直接使用 HTML5 的 <details>/<summary> 標籤來製作可展開的 FAQ?
答: <details> 與 <summary> 確實是 HTML5 提供的原生解決方案之一。它可以輕鬆實現展開/收合的交互,而且不需要任何 JavaScript:瀏覽器會自動幫 <details> 元素實現點擊展開和收合內容的功能。所以,用 <details> 來做 FAQ 在很多情況下是可行且方便的。使用 <details> 的優點是簡單快速,預設就有箭頭圖示和展開動作,同時對無障礙也做了考量(螢幕閱讀器會識別 <details> 是可展開區塊)。然而,這種方法的彈性相對沒那麼高。如果你想完全自定義展開收合的樣式或行為,用 <details> 可能會受到一些限制(例如不同瀏覽器對 <details> 樣式控制的支援程度不一)。在本篇教學中,我們選擇 <dl> 手動實作的方式,主要是出於教學目的:示範如何運用語意化標籤構造 FAQ,以及透過簡潔的 JS 控制來掌握互動的細節。如果你的專案追求語意結構的清晰且希望對樣式/動作有完全的掌控,那 <dl> + JavaScript 的方式會比較適合;但如果你需要快速實現一個可折疊區塊,而且對預設樣式和瀏覽器行為沒有意見,那 <details> 無疑是更省事的選擇。總而言之,兩種方式各有千秋 —— 選擇 <dl> 或 <details> 取決於你的需求:想要高度自定義和學習原理,就用我們本文介紹的方式;想要方便快捷,<details> 也是不錯的解決方案。
結語
透過上述步驟,我們完成了一個從語意結構到互動效果都相當完善的 FAQ 問答頁範例。你學會了如何使用 <dl>/<dt>/<dd> 來組織問題和答案,並利用 CSS 美化列表、用簡潔的 JavaScript 程式碼控制問答的展開與收合。這個示範不僅實現了功能,也體現了良好的開發實踐——語意化的 HTML 結構讓內容更有意義,簡明的腳本讓網頁不需依賴繁重的框架就能提供互動。
現在,面對自己的專案,你大可以嘗試將這套方式應用進去,或者進一步擴充:例如,為展開/收合加入動畫效果(可以用 CSS 的過渡 transition 來實現平滑的伸縮動畫)、修改腳本讓同一時間只允許一個問題展開(類似手風琴效果,需在點擊時先關閉其他打開的項目)、甚至將 FAQ 清單做成可重複利用的元件等等。這些延伸挑戰都非常歡迎你去嘗試!
希望這篇教學讓你對 <dl> 等語意化標籤有了新的認識,也增進了你製作互動網頁元件的信心。現在就動手試一試吧,相信不需要多久,你就能為你的網站打造出一個實用又專業的常見問答頁面。Happy coding,期待你把更多創意應用在未來的開發中!