前端品質
任何使用者面對的網頁 UI 的品質標準。這是硬性要求(無障礙、效能、行動優先),而非風格偏好。審查能發現對真實使用者至關重要的錯誤——緩慢的頁面、損壞的鍵盤導航、載入時會移動的版面。
模型路由
當模型需要對 UI、UX、視覺層級、無障礙文案或互動細節進行評論或重寫時,請使用操作者的前端偏好設定:
source "$WALTER_OS_HOME/scripts/walter/lib/model-router.sh"
frontend_model=""
walter_model_resolve frontend frontend_model
預設偏好為 Claude。操作者可以在 ~/.config/walter-os/overlay/personal.env 中將此別名指向另一個 LiteLLM 路由。
此技能會自動觸發於涉及前端的差異比較。對於從零開始建置的登陸頁面,請使用 landing-page-fast(它包含這些規則,但會提供框架)。
為何這對該操作者特別重要
- [Project A] 的使用者是阿根廷的中小企業供應商——許多人使用手機,且經常使用 3G/4G 連線,訊號間歇中斷。網站緩慢 = 使用者離開。WCAG 之所以重要,是因為有些使用者技術能力較低且有視力障礙。
- [Project B] 的使用者包括殘疾患者。WCAG 不是「選配」,而是可用性的必要條件。
- [Company] 文件站點 的讀者是一群老練的開發者,他們會在網站緩慢或鍵盤操作損壞時立即離開。
無障礙(WCAG 2.2 AA — 必要)
鍵盤
- 每個可互動元素都必須可透過 Tab 鍵觸及。按鈕、連結、表單欄位、自訂控制項。手動進行 Tab 測試;如果有任何控制項被跳過,則為 BLOCKER。
- 焦點可見。
:focus-visible的輪廓必須明顯。請勿在沒有替代方案的情況下設定outline: none。 - 邏輯的 Tab 順序。閱讀順序與 DOM 順序一致;避免使用
tabindex值 > 0(這會破壞自然流程)。 - 跳過連結。每個頁面的第一個可聚焦元素都應該是「跳到主要內容」。
- Escape 鍵關閉模態框。在模態框關閉前,將焦點限制在內部。
語意化 HTML
- 使用
<button>表示動作,使用<a>表示導航。永遠不要為這兩者使用<div onClick>。 - 標題層級分明:每個頁面一個
<h1>;<h2>...<h6>不能跳過層級。 - 地標:使用
<header>、<nav>、<main>、<footer>。只有在沒有合適的語意元素時才使用 ARIA 角色。 - 列表使用
<ul>/<ol>。不要用<div>來偽裝列表。 - 表單控制項須有
<label>。for屬性需與id相符。
色彩與對比度
- WCAG AA 對比度最低要求:內文 4.5:1,大字型(18pt+ 或 14pt+ 粗體)3:1,UI 元件與圖形 3:1。
- 顏色不是唯一指示:錯誤狀態應顯示圖示 + 文字 + 顏色,而不只是紅色邊框。
- 使用模擬色盲測試。使用 Stark、axe DevTools 或瀏覽器開發工具的色覺模擬器。
表單
- 每個輸入欄位都有可見的標籤。佔位符(Placeholder)不是標籤。
- 錯誤訊息需要以程式方式關聯,使用
aria-describedby。 - 必填欄位需標記。同時使用視覺方式(
*或「必填」)和程式方式(aria-required="true"或required)。 - 驗證錯誤不會在獲得焦點時消失。錯誤應持續顯示,直到修正或關閉。
- 成功狀態需確認。提交後,螢幕閱讀器使用者需知道操作成功。
圖片與多媒體
- 每個
<img>都有alt屬性。裝飾性圖片使用空值(alt="");內容性圖片需具描述性。對於 AI 生成的圖片:描述圖片中的實際內容,而非其提示詞。 - 影片/音訊需要字幕/逐字稿。
- 不要自動播放含聲音的內容。
- 動畫需尊重
prefers-reduced-motion:@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
工具
- 開發模式下使用
@axe-core/react— 在控制台記錄無障礙問題。 - 使用
eslint-plugin-jsx-a11y— 在建置時捕獲問題。 - 上線前進行手動螢幕閱讀器測試:VoiceOver(Mac)、NVDA(Windows)、TalkBack(Android)。
- CI 中的 Lighthouse 無障礙分數 ≥ 95。
效能 — 核心網頁指標
這是 Google 用來排名的 3 個指標。需通過全部三個才能被視為「良好」:
LCP(最大內容繪製)— 載入速度
目標:3G 網路下 < 2.5s。對 [Project A] 的實際情況而言,由於阿根廷行動網路比中位數慢,標準會更嚴格。
方法:
- 預載 LCP 圖片:使用
<link rel="preload" as="image" href="...">。 - 無阻塞渲染的資源:延遲非關鍵的 JS,內聯關鍵 CSS。
- 自託管字型,搭配
font-display: swap,或使用系統字型堆疊。 - 靜態資源使用 CDN:Vercel、Cloudflare R2、Bunny.net。
- 使用 HTTP/2 或 HTTP/3:Vercel/Cloudflare 的預設設定。
- 壓縮圖片:使用 WebP/AVIF 格式,並根據視口大小調整尺寸。
- 特別最佳化主視覺圖片:它幾乎總是 LCP 的元素。
INP(與下一次繪製的互動)— 回應性
目標:p75 百分位 < 200ms。2024 年取代了 FID。
方法:
- 互動期間主執行緒無超過 50ms 的長時間任務。
- 延遲水合(Hydration)(Astro islands、Next.js 串流、Qwik)。
- 使用 Web Workers 處理大量計算。
- 對輸入處理器進行去抖(Debounce)/節流(Throttle)。
- 避免使用
dangerouslySetInnerHTML處理大段字串 — 解析會阻塞執行緒。 - 僅在實際測量到效能問題時才使用
useMemo/memo,不要預先使用。
CLS(累計版面配置位移)— 視覺穩定性
目標:< 0.1。
方法:
- 圖片和影片標籤須包含
width+height(瀏覽器會保留空間)。 - 為廣告/嵌入內容保留空間,使用 min-height。
- 不要在現有內容上方插入內容:通知橫幅應放在摺疊以下,或透過 transform 方式推下,而不是在 DOM 中的上方插入。
- 網頁字型:使用
font-display: swap+size-adjust來比對字體規格,或者如果可行,使用font-display: optional。 - 骨架畫面(Skeleton screens) 的尺寸應與實際內容相符。
套件大小
- 初始 JS 預算:登陸頁面 < 150KB gzipped,應用程式外殼 < 250KB。
- 按路由進行程式碼分割(Next.js、Astro、SvelteKit 預設執行此操作)。
- 對非關鍵的大型依賴項使用動態匯入(圖表、編輯器)。
- 稽核依賴項:使用
bundle-analyzer或next-bundle-analyzer。丟棄你只使用一個元件的 10MB UI 函式庫。 - 確保 Tree-shaking 正常運作:只匯入你需要的部分(使用
import { thing } from 'lib',不要使用import lib from 'lib')。
載入模式
- 預先連接到所需的來源:使用
<link rel="preconnect" href="...">。 - 在滑鼠懸停/聚焦時預先擷取可能的下一個頁面(Next.js 有內建此功能)。
- 對摺疊以下的圖片進行延遲載入:使用
loading="lazy"。 - 對 iframe 進行延遲載入:使用
loading="lazy"。 - 使用 Service Worker 實現離線優先(在合適的情況下——[Project A] 受益,行銷頁面則不適用)。
狀態 — 每個元件需處理全部五種
對於任何由資料驅動的 UI,若未處理任何一種狀態,則視為 BLOCKER:
- 載入中 — 骨架畫面或旋轉圖示。不是空白畫面。不是版面位移。
- 空資料 — 首次使用、無資料的狀態。附有引導填入資料的 CTA。
- 錯誤 — 清晰的訊息、重試按鈕、不向使用者顯示堆疊追蹤。錯誤需記錄到 Sentry。
- 部分/過時 — 當資料來自快取或部分擷取時。
- 成功 — 正常路徑。
列表範例:
if (isLoading) return <ListSkeleton />
if (error) return <ErrorState onRetry={refetch} />
if (data.length === 0) return <EmptyState cta={...} />
return <List items={data} />
如果你的元件在差異比對中只顯示了成功狀態,請問:其他 4 種狀態在哪裡?
行動優先
- 首先為 360px 寬的畫面進行設計,再向上放大。
- 觸控目標 ≥ 44×44px(Apple HIG)或 48×48px(Material Design)。
- 無僅限滑鼠懸停的互動:任何可透過滑鼠懸停使用的功能,也必須有可聚焦/觸控的路徑。
- 在真實裝置或啟用限制的 Chrome DevTools 上進行測試:3G 網路、4 倍 CPU 降速。
- 表單無需縮放即可操作:輸入欄位的
font-size須為 16px 或更大(否則 iOS 會在聚焦時自動縮放)。
工具參考
CI / 合併前:
- Lighthouse CI,針對每個指標設定預算。
@axe-core/cli或 Lighthouse 無障礙子集。bundlewatch,阻止套件大小超出預算的 PR。- 視覺回歸測試:使用 Chromatic(Storybook)、Percy 或 Playwright 進行螢幕截圖比對。
本地端:
- Chrome DevTools 的 Performance 和 Lighthouse 面板。
unlighthouse用於全站稽核。@unjs/check-vitals用於一次性檢查核心網頁指標。
輸出格式
**[BLOCKING|WARN|NIT] [FE-N] <一行摘要>**
位置:`path/to/Component.tsx:42-58`
類別:<a11y | perf | states | mobile | semantic>
影響:<影響到的使用者 / 情境 / 指標>
修復:<具體的修改方式,如果可行請附上程式碼>
驗證:<如何確認修復 — 執行 Lighthouse / 手動測試 / 等>
嚴重程度:
- BLOCKING:違反 WCAG AA、核心流程損壞、核心網頁指標落在「差」的範圍。必須修正。
- WARN:偏離最佳實務、效能回歸但尚未對使用者造成明顯影響。
- NIT:有改進機會(更小的套件、更好的骨架畫面)。
硬性規則
- 永遠不要使用
<div onClick>來當作按鈕。 - 圖片永遠不能缺少
alt屬性。 - 真實內容不能造成版面位移。 務必保留空間。
- 永遠不要自動播放含聲音的內容。
- 必須尊重
prefers-reduced-motion。
此技能不涵蓋的範圍
- 後端(請使用
web-security-baseline)。 - 資料庫結構 / 查詢(請使用
data-migration-safety)。 - 品牌識別 / 視覺設計(請使用
brand-creation)。 - 建置全新登陸頁面(請使用
landing-page-fast,它會提供框架)。
參考資料
- WCAG 2.2 快速參考
- web.dev 核心網頁指標文件
- web.dev 效能學習路徑
- Heydon Pickering 的《包容性元件》(Inclusive Components)
- A11y Project 檢查清單