標記優先:先把結構講清楚,行為再說
我寫一個畫面的時候,習慣先問結構長怎樣,而不是先問要用哪個元件。這順序聽起來小事,但它決定了後面好不好維護、好不好除錯。多數框架教學是反過來教的,先給你一個元件,再叫你把資料塞進去,結構反而被元件的生命週期跟狀態管理糊掉,你最後對「瀏覽器實際渲染出什麼」沒了直覺。
更正(2026-11-02 18:45):初始值與目前值的分岔改為說明最明顯的是 value/defaultValue、checked/defaultChecked 這類表單狀態,刪去 class/classList 的類比;範例註解改為 getAttribute("value")。修正建議:Codex(gpt-6-astra),Claude 驗證。
先有結構,再包行為
HTML、Markdown、XML 這類標記語言,本質是在描述「這份文件由哪些東西組成、它們的層級關係是什麼」。這是一種宣告式的結構表達,跟「要怎麼做」無關。我偏好讓這層先穩下來:標題就是標題,清單就是清單,表單就是表單,語意對了,無障礙、SEO、可讀性大半就直接拿到。
行為這層應該是輕量包上去的。一個按鈕點下去發一個請求、把回來的片段塞進某個容器,這種互動其實不需要先有一套元件框架。htmx 把這件事做得很俐落,互動寫成 HTML attribute,伺服器主導要回什麼,client 端幾乎不留狀態。我不是說所有東西都該這樣寫,高互動、離線、canvas、local-first 那類應用本來就需要 client 端狀態管理,這沒得避。但對大部分以內容跟表單為主的頁面,預設值該是「結構優先、行為薄一層」,而不是反射性地先架一個 SPA。
當你從 server 回傳的是「一段已經長好的 HTML」,而不是「一包 JSON 再讓 client 重新組 DOM」,心智負擔差很多。前者你打開 devtools 看到什麼就是什麼,後者你得在腦中模擬一遍 render 流程才知道畫面為何長這樣。
attribute 不是 property
有個區別被框架糊掉很久,但其實很關鍵:HTML attribute 跟 DOM property 不是同一件事。
attribute 是寫在標記裡的值,瀏覽器解析 HTML、建立 DOM 節點後,程式在執行期間讀寫的是節點上的 property。兩者常常同名,有些一直同步,有些會分岔,分岔最明顯的是表單狀態。以 input 為例,在 HTML 寫下 value="hello" 後,使用者輸入新內容會改變 element.value,element.getAttribute("value") 仍是 hello:前者是當下狀態,後者對應初始值 defaultValue。checked 與 defaultChecked 也是同樣的分界。attribute 本身也能用 setAttribute 修改;class 與 classList 則一直同步,classList 是同一個 class attribute 的 token 介面,改一邊另一邊立刻跟著變。
<input value="hello">
<!-- 使用者改成 world 之後 -->
<!-- element.value => "world" (DOM property,活的) -->
<!-- element.getAttribute("value") => "hello" (HTML attribute,初始) -->
框架的抽象只是把這個分界「減少你直接碰它的機會」,沒有消除它。你在 React 寫 value={state}、在別的框架做雙向綁定,底層還是有人在幫你把 property 跟某個狀態源同步。等到哪天綁定行為怪怪的、表單值對不上、第三方套件直接操作 DOM 跟框架打架,你就得回到這個分界去想:現在是 attribute 沒更新,還是 property 被誰偷改了。懂這條線的人,除錯速度差很多,因為他知道該去 inspect 哪一邊。
從畫 DOM 樹開始
實務上我會建議,設計一個畫面先在紙上或腦中把 DOM 樹畫出來:根節點是什麼、底下分幾塊、每塊的語意標籤是什麼、哪裡需要可互動。這棵樹畫清楚了,要套什麼框架、要不要拆元件,都是後面的事,而且會變得很自然,因為元件邊界往往就落在樹的自然分界上。
這樣做維護體驗好很多。出問題的時候,你的 mental model 跟 devtools 裡的 Elements 面板是對齊的,你看著真實 DOM 就能往回推;而不是對著一堆元件名稱跟 props,猜它們最後展開成什麼。除錯本質上是在「我以為的結構」跟「實際的結構」之間找落差,這兩者越接近,找落差越快。
還有一個長期觀察。軟體疊得越厚,工具鏈越多層,使用者跟工程師反而會回頭找更薄、更透明的表達方式。純文字、Markdown、各種標記語言之所以耐久,是因為它們可以直接讀、可以 diff、可以丟進版本控制看每一行怎麼變的。一個用十層抽象生出來的畫面,壞掉的時候你很難 diff 出「到底哪一層改了什麼」;一份 HTML 或 Markdown,壞了你一眼就看到。
我偏好結構優先,原因很單純:層級少、責任清楚,結果也直接擺在眼前,不必先跑一遍框架才能理解。這讓畫面更容易控制,也更容易解釋。
補充筆記
- 設計畫面先描述結構,再包行為,不要反過來從框架元件開始想。
- 表單的
value、checkedattribute 對應初始值,DOM property 是執行期活的狀態,class與classList則一直同步;框架只減少、沒消除這條分界。 - 懂 attribute / property 分界的人除錯快,因為知道該 inspect 哪一邊。
- 從畫 DOM 樹開始,mental model 跟 devtools 對齊,找落差就快。
- 軟體越疊越厚,純文字與標記語言因為可讀、可 diff、可版控而更耐久。
想法與技術判斷出自 Sheng,和 Claude 一起起草 · 列入 20260613 blog 翻新計劃,新漆未乾。