開發紀錄
看起來像按鈕,不代表它真的該是 <button>
從本站的產品入口、文章目錄和抽屜控制,說明連結、動作按鈕與表單送出如何共用外觀,卻保留不同的 HTML 語意與瀏覽器行為。
- HTML
- 介面語意
- Astro
- 元件設計
「查看產品」和「開啟目錄」可以有一樣的圓角、邊框與 hover 效果,但點下去做的事不同。前者前往另一份內容,後者改變目前頁面的介面狀態。
如果兩者都因為外觀像按鈕而輸出 <button>,導覽就容易變成一段點擊腳本;反過來,若把所有控制都寫成 <a href="#">,連結又會被拿來代替沒有目的地的操作。
本站使用共用 Button 元件,但我在使用它時先確認操作,再選擇輸出的 HTML。元件名稱描述的是外觀,不該替所有使用點決定語意。
前往內容,先給它一個真實的目的地
HTML 的 <a> 搭配 href 可以建立連往頁面、檔案或同頁位置等目標的超連結。[1] 本站首頁的產品入口、文章頁的「返回筆記列表」,以及產品頁的「看看日序 Demo」,都屬於這類用途。
它們可以做成醒目的按鈕外觀,但輸出仍是 <a>。共用元件在這些使用點傳入 as="a" 與 href,讓目的地留在 HTML,而不是只藏在點擊事件裡。
這樣,讀者可以透過瀏覽器原本的連結操作開啟內容。本站的元件導入紀錄已經說明這個選擇;這篇進一步處理的是,每次放置控制時要怎麼判斷,而不是重新介紹安裝流程。
下面是用途示例,並非完整頁面:
<a href="/products/daily-order">查看產品</a> <a href="/notes">返回筆記列表</a>
同頁移動也可以是導覽。日序介紹頁的「了解日序怎麼運作」連到 #journey,帶讀者前往後面的說明區塊;它不需要因為沒有換頁,就改成動作按鈕。
改變目前狀態,才是動作控制
開啟文章目錄抽屜沒有另一個內容網址。它的工作是把目前頁面中的控制打開,因此本站使用 <button type="button">。
關於頁的頭像放大也是動作:它改變同一份頁面裡的介面狀態,不是前往圖片網址。
HTML 的 <button> 是可透過滑鼠、鍵盤等輸入方式操作的互動元素。[2] 不過,選對元素只是起點,抽屜與放大視窗仍有各自的焦點、關閉方式和狀態同步責任。
因此,我不會把「已經用 button」當成互動完成的證據。元件可以提供外觀與基本結構,實際使用點仍要接上它所承諾的操作。
送出表單,必須另外說清楚
type="button" 和 type="submit" 不應被當成可有可無的裝飾。在一般與表單關聯的情境下,沒有指定適當 type 的按鈕可能觸發表單送出;單純操作介面的控制應明確使用 type="button"。[2]
本站的本地 Button 元件在輸出 <button> 時預設給 type="button",呼叫端仍能明確傳入 type="submit"。這是目前專案的實作,不是所有元件庫都會採用的預設。
例如,下列是表單用途示意,不代表本站已新增這份表單或儲存 API:
<form>
<button type="button">顯示填寫說明</button>
<button type="submit">送出資料</button>
</form>
前者只負責顯示說明;後者表達送出意圖。至於資料驗證、請求失敗與重複送出,要由實際表單另外處理,不能因為出現了 submit 按鈕就視為具備這些功能。
不要讓 variant 替你選元素
本站的 Button 同時有 variant="link" 和 as="a",兩者控制不同事情。
variant="link" 選的是外觀。若沒有指定 as,元件仍預設輸出 <button>。只有 as="a" 才把元素切成連結,並由使用點提供 href。
這種分離讓文字型動作按鈕不必假裝是連結,也讓醒目的頁面入口不必失去導覽語意。但它要求開發者不能只看 variant 名稱。
我會沿著目前元件的契約檢查:
| 使用意圖 | 選擇 | 需要確認的內容 |
|---|---|---|
| 前往頁面或同頁區塊 | as="a" |
真實 href 與目的內容 |
| 開啟或關閉介面 | 預設 button 或 as="button" |
type="button"、操作與狀態 |
| 送出表單 | button 加 type="submit" |
表單關聯與實際送出流程 |
這張表是本站常見用途的判斷,不是所有互動的完整分類。例如,原生 details 的開關應由 summary 承擔;不能把任何可點擊區域都硬塞進 button 或 anchor 其中一種。
腳本可以增強連結,不必取消它的身份
本站文章目錄輸出的是 href="#段落識別字" 的原生連結。瀏覽器腳本再補上捲動效果、目前段落指示,以及手機目錄抽屜的關閉動作。
這裡的順序很重要:HTML 先有目的地,腳本再增強行為。文章目錄不是先寫一串只靠事件才能工作的文字,再要求腳本替它們補出用途。
但有真實連結不表示所有周邊控制都能在沒有 JavaScript 時運作。本站手機目錄另有 noscript 的原生連結列表;抽屜開關與捲動指示則仍屬於腳本增強。驗證時應把這幾件事分開。
檢查輸出,而不是停在元件名稱
從畫面很難分辨一個圓角控制究竟是 <a> 還是 <button>。我會回到實際 HTML 看標籤、href、type 與控制名稱,再確認它們是否符合使用意圖。
接著才是操作檢查:連結能不能到達正文,按鈕是否真的開啟目錄,圖示控制是否有能理解的名稱,以及鍵盤操作是否符合用途。這些都需要針對實際使用點驗證,不能拿另一顆按鈕的成功結果代替。
共用樣式可以減少重複,但「查看內容」與「改變狀態」仍然是不同責任。我希望元件幫我們保持外觀一致,同時讓 HTML 把這個差異留下來。
紀錄範圍
本文依據本站共用 Button 的本地實作、產品頁連結、關於頁控制與文章目錄整理。表單區塊是用途示例,不代表本站已有新的資料送出功能;本文也未宣稱完成所有瀏覽器、輔助科技或互動路徑的驗收。元件導入與隔離測試的歷史另見〈導入 bejamas/ui:先加一個 Button,不讓元件庫接管網站〉。
Sources
[1] https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a [2] https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button