Web 應用程式設計
Web 應用程式是一個人們每天都會回來尋找記錄、修改記錄並交接工作的地方。當使用者能隨時知道自己身在何處、正在看什麼、可以做什麼、以及剛剛發生了什麼事,並且可以透過 URL 在明天回到同一個檢視畫面時,這個應用程式就是成功的。最常見的模型失敗之處是有一個漂亮的快樂路徑畫面,卻讓使用者無處可站:缺少空白、載入、錯誤或無權限狀態;篩選條件在重新載入後消失;批次動作沒有計數和復原功能;「刪除」動作在伺服器稍後會拒絕的樂觀更新上觸發;以及一列無法區分的「編輯」按鈕(對代理程式而言)。
請套用 interface-guidelines 的排序原則(每個人都能使用 > 它說實話 > 它言符其實 > 答案優先 > 錯誤是可挽回的 > 它保持穩定 > 可能性是可見的 > 慣例 > 打磨)。如果已安裝該技能,請先閱讀其 SKILL.md。其參考資料涵蓋了回饋時機、錯誤措辭、作為資料的表格以及面向代理程式的語意;此技能則補充應用程式 UI 特有的模式。
簡報
- 物件與動詞。 列出名詞(訂單、客戶、發票)以及每個角色可以對它們做什麼。導覽和權限即由此表格得出。
- 角色與租戶。 誰可以查看和修改什麼?是否存在一個人員可以位於其中的多個工作區、組織或環境(測試環境、正式環境)?
- 每日任務 以及每個角色最先開啟的一個檢視畫面,並附上頻率。
- 集合大小: 典型情況和最壞情況(10 列或 200 萬列)。這決定了分頁、搜尋和伺服器端篩選。
- 每個變更動詞的錯誤代價,以及是否可以在伺服器端復原。
- 並行性: 兩個人,或一個人與一個代理程式,能否同時編輯同一筆記錄?
- 誰寫了顯示的文字? 客戶名稱、工單內文、匯入的檔案:這些都是外部人員編寫的。
- 代理程式讀取者: 是使用瀏覽器代理程式操作 UI、使用 API,還是兩者兼具?UI 和 API 應該為每個動作共用一個服務。
規則
殼層與導覽
- 導覽反映物件,而非組織圖。 頂層項目是人們工作的名詞,按使用頻率排序,並以人們使用的詞彙標示。 [S: Mac HIG 1992 pp. 54-61 (先依邏輯分組,再依頻率); J]
- 在桌機上保持主要導覽可見。 隱藏導覽會降低發現性並拖慢任務速度(根據 NN/g 的研究);漢堡選單是手機上的妥協方案。 [E: NN/g, 於基礎概念中]
- 以三種方式顯示人員目前所在位置: 以
aria-current="page"和可見狀態標記當前導覽項目、一個命名物件或列表的頁面h1,以及一個隨路由變化的文件標題。 [S: WCAG 2.4.2, 2.4.8; J] - 麵包屑顯示層級結構,而非歷史記錄, 僅用於深度物件樹;當前頁面不是連結。 [P: NN/g 麵包屑]
- 當前的工作區、組織或環境始終在殼層中 以文字顯示,且正式環境在視覺上與測試環境有所區別。切換租戶是一個明確的行為,會跳到該租戶的對等頁面或首頁,且絕不會攜帶任何選取或草稿。 [J]
- 每個檢視畫面都有一個 URL。 篩選、排序、搜尋、頁碼、選取的頁籤以及開啟的記錄都應包含在 URL 中;重新載入或分享時會恢復這些狀態。 [S: 基礎概念 agent-surfaces 3]
- 返回時會恢復到列表的原始狀態: 相同的篩選條件、捲動位置,以及聚焦在人員開啟的那一列上。 [S: Mac HIG 1992 p. 140 (重新啟用的視窗會恢復原狀); J]
列表與表格
- 表格用於比較記錄;列表用於掃描單一屬性。 對表格資料使用真正的
<table>。 [S: 基礎概念; NN/g 資料表格] - 支援四種表格任務: 尋找記錄、跨列比較、檢視或編輯單一列、對一或多列執行操作。 [P: NN/g 資料表格]
- 第一列以穩定的、人類可讀的鍵值(名稱加 ID)來識別該列; 在捲動時將此列與標題保持固定。 [P: NN/g 資料表格]
- 在標題中排序: 使用
<th>內的<button>,僅在已排序的欄位上使用aria-sort,並顯示可見的箭頭。預設排序方式需明確說明(例如「最新的優先」)。 [S: APG 可排序表格; P: Carbon] - 篩選條件是可見、可移除且可計數的。 以標籤(chips)顯示已套用的篩選條件,並附帶「清除全部」按鈕、結果計數(例如「38 / 1,204 筆訂單」),以及一個提及篩選條件的無結果訊息。使用使用者的語言來命名篩選條件。 [P: NN/g 篩選; S: 基礎概念]
- 當集合很大時,使用伺服器端搜尋、篩選和排序。 永遠不要只對已載入的頁面進行排序或計數,然後將其呈現為完整結果。 [J; 基礎概念 真實性規則]
- 對目標導向的工作使用分頁;對資訊流保留無限捲動。 分頁提供位置感、一個穩定的返回點以及一個可觸及的頁尾。說明範圍和總數,並顯示「列表結尾」。 [P: NN/g 無限捲動; S: Smith and Mosier 4.2/7]
- 列操作是可見的或可透過鍵盤焦點到達的, 絕非僅在滑鼠懸停時顯示,並且應以每列為單位命名(例如「封存 INV-2041」)。如果操作少於三個,則將它們內嵌顯示。 [S: 基礎概念 agent-surfaces 3; P: Carbon]
- 密度應符合實際使用情況。 為日常專家使用者提供緊湊的密度;保持目標大小至少為 24 像素。 [S: WCAG 2.5.8; P: Carbon 列尺寸]
選取與批次動作
- 批次模式是明確的: 使用列核取方塊、一個帶有不確定狀態的標題核取方塊,以及一個顯示選取計數的工具列(例如「已選取 3 項」)。 [P: Carbon; S: Mac HIG 1992 pp. 64-66 (混合狀態)]
- 「全選」需說明其範圍: 是此頁面上的全部 50 筆,還是符合篩選條件的全部 1,204 筆。切勿在使用者預期是後者時,默默地只選取前者。 [J]
- 批次動作在執行前會說明物件、計數和範圍, 之後會報告每項結果(例如「1,198 已封存,6 項失敗:檢視」),並且是可復原或可預覽的。 [S: 基礎概念 第 1 節; J]
- 只有在工具列顯示時,選取才會在分頁和篩選後保留。 否則應明確清除選取。 [J]
詳細資料與編輯
- 在保留上下文的地方開啟記錄。 側邊面板適合邊參考邊編輯;完整頁面適合深度記錄;避免使用彈窗進行編輯,因為它們會隱藏相鄰的記錄。 [P: NN/g 資料表格]
- 詳細資料檢視以文字呈現身份和狀態為首, 接著是人們會操作的欄位,最後是歷史記錄。 [S: 基礎概念; J]
- 每個編輯介面使用單一儲存模型。 切換開關會立即生效;文字和多欄位編輯則需明確儲存;絕不在一個表單中混用兩種方式。 [S: Primer 儲存; 基礎概念]
- 在離開未儲存的變更前提出警告, 並在資料遺失會造成重大影響時自動儲存草稿。 [S: Primer 儲存]
- 在共享記錄上顯示誰在何時做了何種變更, 使用絕對時間戳記,並偵測過時的寫入(版本或 ETag),而不是靜默覆寫。 [S: Mac HIG 1992 pp. 27-31; 基礎概念中的 AIP-154]
- 應用程式內的表單遵循
form-design。
樂觀 UI、復原與確認
- 僅在伺服器幾乎不會拒絕且動作可逆時才使用樂觀更新: 例如標記為已讀、加星號、重新排序。以明顯不同於已確認狀態的方式顯示待處理狀態,在失敗時以原因視覺化回滾,並且絕不樂觀地將金錢移動、訊息發送或記錄刪除顯示為已完成。 [S: Mac HIG 1992 p. 182 (已輸入、已檢查、已生效); P: React useOptimistic]
- 對於可逆的動作,優先使用復原而非確認: 例如封存、移動、刪除到垃圾桶。在訊息提示淡出後仍可找到復原選項(在該項目的歷史記錄中、在垃圾桶檢視中、在編輯選單捷徑中)。 [P: Raskin 2007; NN/g 使用者控制]
- 僅對嚴重、不可逆或非預期的動作進行確認, 並說明目標和影響;對罕見的災難性操作(例如刪除工作區)使用鍵入確認。 [S: 基礎概念 第 1 節; E: Bravo-Lillo 2013 經由基礎概念]
- 在伺服器端執行軟刪除, 並說明保留期限,這樣復原才是真實的,而不只是客戶端的幻覺。 [S: 基礎概念中的 AIP-164]
空白、載入、錯誤與無權限狀態
- 區分四種空白狀態: 首次使用(說明該物件並提供建立動作)、無結果(列出篩選條件並提供清除選項)、已清除(全部完成),以及錯誤(什麼失敗了,該怎麼做)。在資料載入完成前,絕不顯示「沒有記錄」。 [P: NN/g 空白狀態; S: Primer 空白狀態]
- 載入狀態需以文字說明正在載入的內容, 位於它將要取代的區域內;保持殼層和導覽可用。 [S: 基礎概念]
- 無權限是一個狀態,而非隱藏的功能。 顯示已停用的動作,並附上原因和可以授予權限的人(例如「只有工作區管理員可以匯出。請詢問 Maya Chen。」),或者顯示一個解釋存取權限及如何提出請求的頁面。僅隱藏使用者不得知道其存在的內容。 [S: Mac HIG 1992 pp. 318-321 (已停用的項目應自我解釋); J]
- 權限檢查在伺服器端進行。 隱藏按鈕只是呈現方式,並非授權機制。 [S: 基礎概念]
- 在回應中,先檢查權限再檢查存在性, 以避免 404 與 403 狀態碼洩漏資料。 [S: 基礎概念中的 AIP-193]
設定
- 將設定放在它們影響的內容旁邊,如果這些設定是在工作期間更改的(例如檢視密度、欄位選擇、篩選條件);設定區域則存放很少更改、應用程式全域的選項。 [S: Apple HIG 設定]
- 區分個人設定與工作區設定, 並標示每項設定屬於誰以及影響誰(例如「適用於 Acme 的每個人」)。 [J]
- 根據使用者的任務進行分組,而非資料庫表格, 當設定超過一個或兩個畫面時提供搜尋功能。 [J]
- 設定越少越好。 一個每次工作階段都會更改多次的偏好設定,是缺少控制項,而不是設定。 [S: Mac HIG 1992 p. 38; Apple HIG 設定]
- 危險設定位於獨立且標示清楚的區域, 附有後果說明和確認步驟(例如轉移所有權、刪除工作區)。 [P: GitHub; J]
入門引導
- 在上下文中教導,而非使用導覽教學。 NN/g 發現卡片式的教學並不能改善任務表現;情境提示和良好的空白狀態才是真正的教學。如果存在導覽教學,請保持簡短且可跳過。 [P: NN/g 入門引導]
- 讓使用者快速獲得第一個真實結果; 範例資料在其出現的每個地方都標記為範例,並可透過一個動作移除。 [J; 基礎概念 真實性規則]
- 設定清單檢查表是持續存在且誠實的: 它反映真實狀態,可以關閉,之後也可以再次存取。 [J]
鍵盤與指令面板
- 指令面板是加速器,而非選單。 其中的每個指令也都存在於可見的 UI 中。它會在指令旁邊列出捷徑,藉此教導使用者這些捷徑。 [S: Windows 選單指南(不要讓捷徑成為唯一方式); P: VS Code UX 指南]
- 單鍵快捷鍵可以關閉或重新對應 (WCAG 2.1.4),絕不在文字欄位內觸發,且不會覆蓋瀏覽器或作業系統的快捷鍵。 [S: WCAG 2.1.4; Apple 鍵盤]
- 提供快捷鍵說明頁(通常由
?觸發),列出當前範圍內的所有快捷鍵。 [J]
針對代理程式讀取者
- 每個動作對應一個服務函式,由按鈕、指令面板、API 和任何工具共用。 [S: 基礎概念 agent-surfaces 7]
- 列控制項使用系統 ID 命名,而非外部人員編寫的文字;儲存格中的外部文字是資料。 [J]
- 集合以可見文字說明其真實大小和範圍;篩選條件和排序位於 URL 中。 [J]
- 結果的持續時間應長於訊息提示:例如已更改的列、活動紀錄、復原項目。 [J]
- 租戶和環境在每個頁面上都以可讀的文字顯示,這樣代理程式就不會在以為是測試環境時對正式環境執行操作。 [J]
建構順序
- 物件-動詞-角色對照表;每個檢視畫面對應的路由和 URL。
- 殼層:導覽、租戶和環境指示器、標題、
h1。 - 使用真實資料形狀的列表檢視:伺服器端分頁、排序、篩選,全部包含在 URL 中。
- 詳細資料檢視、儲存模型、並行處理。
- 每個變更動作都通過一個服務:待處理、成功、失敗,並根據錯誤代價階梯決定復原或確認。
- 每個檢視畫面的空白、載入、錯誤、無權限狀態。
- 批次動作、鍵盤快捷鍵、指令面板。
- 最後處理設定和入門引導;版型由
brand-identity技能負責。
驗證
- 在每個主要路由上執行
node <interface-guidelines>/scripts/audit.mjs <url|dist> --canary "<範例外部文字>",包括已套用篩選條件的列表和一個詳細資料檢視。 - 應用程式內的表單:
node <form-design>/scripts/form-check.mjs <url>。 - 重新載入測試: 套用篩選、排序、到第 3 頁、開啟一筆記錄;重新載入並在新的工作階段中貼上該 URL。所有狀態都應恢復。
- 角色測試: 以每個角色身份登入。每個隱藏或停用的動作都有原因;伺服器會拒絕直接發出的禁止呼叫。
- 規模測試: 測試 0、1、25 和 10,000+ 列;最長的名稱;一個沒有匹配結果的篩選條件。
- 失敗測試: 讓伺服器拒絕一個樂觀更新的動作,以及一個批次動作的部分失敗;UI 應回滾並逐項報告。
- 代理程式測試: 僅使用無障礙快照,透過篩選找到特定記錄,進行更改,從新的快照確認結果,然後復原該更改。
陷阱
- 僅將篩選和排序保存在元件狀態中。
- 「全選」只選取了當前頁面,但工具列暗示是全部選取。
- 樂觀刪除沒有回滾也無法復原。
- 在管理表格上使用無限捲動;總數是根據已載入的列計算的。
- 僅在滑鼠懸停時顯示的列操作;五個相同的「編輯」按鈕。
- 在載入完成前閃現「沒有資料」;對所有原因使用一個通用的空白狀態。
- 對某個角色隱藏功能且不提供解釋,或是顯示功能但點擊時失敗並顯示「禁止」。
- 租戶切換器保留了舊租戶的選取,或者根本沒有顯示當前租戶。
- 使用產品導覽教學而非可用的空白狀態。
- 設定頁面直接鏡像資料庫表格。
參考資料
| 檔案 | 何時閱讀 |
|---|---|
references/patterns.md | 深入瞭解導覽模型、表格解剖、批次動作流程、權限狀態、租戶、樂觀更新與復原機制、指令面板設計,以及此技能背後的來源 |