Communitygithub.com

karero/網站設計系統

負責**視覺外觀與效能**層級:行動圖形、深色模式與主題代碼。

網站設計系統 是什麼?

這個技能定義了一個完整的網站設計系統,專注於**視覺外觀與效能**層級。它負責管理行動圖形、深色模式支援以及主題代碼(theme tokens),並輸出並維護 `BRAND.md` 檔案與 `global.css` 中的代碼區塊。此技能強制要求使用現代圖片格式(WebP/AVIF),並確保圖片響應式、延遲/積極載入正確且具備替代文字(alt text)。深色模式為一等公民,不採用硬編碼顏色,而是透過 CSS 自訂屬性實作,並包含無 FOUC(Flash of Unstyled Content)腳本。此外,技能也涵蓋了文字長度響應性(特別針對翻譯內容)、可存取的表格(`stack` / `figures` 類型)、電子郵件混淆(Email obfuscation)以及品牌代碼同步。此技能支援 Astro 專案,並提供對應的測試規格(如 `images.spec.ts`、`tables.spec.ts`、`website-qa`)。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/karero/croftweaver/tree/HEAD/skills/website-design-system

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

網站設計系統 是做什麼的?

負責視覺外觀與效能層級:行動圖形、深色模式與主題代碼。輸出/維護 BRAND.md(範本:new-website 技能的 templates/brand.md)以及該技能 templates/astro/src/styles/global.css 中的代碼區塊。圖片規則如下(透過 Astro 的 astro:assets 使用 WebP/AVIF);images.spec.ts 測試會強制執行這些規則。如需產生圖片資產,請使用 image 技能。

深色模式(一等公民)

  • 使用代碼,而非硬編碼顏色。 所有顏色都透過 CSS 自訂屬性流動;淺色模式是 :root 的預設值,深色模式則在 :root[data-theme="dark"] 下覆寫,另外還有一個 @media (prefers-color-scheme: dark) 區塊給不使用 JavaScript 的訪客。起始模板已包含此確切結構。
  • 無 FOUC 腳本 位於 <head> 中,會在首次繪製之前從 localStorage.theme 或系統偏好設定 data-theme(已在 Base.astro 中連接)。切換開關會寫入 localStorage.theme(起始模板未附帶任何切換開關;如果你新增一個,請在隱私頁面的第 3 節中說明)。
  • 檢查兩種主題的對比度: 每個文字/背景組合都必須通過 WCAG AA 標準(主體文字 4.5:1,大型/UI 元素 3:1)。在淺色模式下通過的顏色在深色模式下通常會失敗——無障礙測試會執行完整的淺色+深色矩陣,因此請務必檢查兩者。

行動與響應式圖形

  • 行動優先: 從 360px 開始設計;觸控目標 ≥ 44px;無水平捲軸。請在 360 / 768 / 1280 解析度下驗證(preview_resize)。
  • 使用現代格式: 對於照片,使用 WebP(或 AVIF)而非 JPEG/PNG。
  • 尺寸應符合顯示區域,而非原始尺寸。 切勿將 2000px 的圖片用於 80px 的插槽;應產生寬度變體並使用 srcset/sizes(或 <picture>)。
  • 避免版面位移: 設定明確的 width/height 屬性,以便在圖片載入前保留其區域(保護 CLS / LCP)。Astro 的 <Image> 會自動設定這些屬性;images.spec.ts 要求這些屬性(僅使用 CSS 的 aspect-ratio 無法滿足測試要求)。
  • 延遲載入 vs 積極載入: 在摺頁以下使用 loading="lazy";LCP/主要圖片(hero image)則使用 loading="eager" 且搭配 fetchpriority="high"(不要對它使用延遲載入)。
  • 每張圖片都需要替代文字(僅在純裝飾用途時使用 alt="")。
  • 字型: 自託管 woff2 格式,搭配 font-display: swap;僅預載入摺頁以上使用的 1-2 種字型。避免因字型延遲交換而導致的版面位移。

文字長度響應性(翻譯文案)

  • 翻譯後文字通常會變長。 德文(以及許多其他語言)通常會比對應的英文文案長 20–35%。一個按鈕、導覽連結或卡片若僅根據英文佔位文字設定大小,當實際翻譯的文案取代它時,便會默默地溢出、難看地換行,或直接截斷。
  • 偏愛彈性寬度。 對於任何包含翻譯文字的元件,應使用 min-width / flex / grid 的 auto/fr 尺寸設定,而不是根據英文字串設定固定 width。
  • 溢出 ≠ 寬度: 彈性尺寸設定無法阻止一個單一的長複合名詞(例如 Datenschutzerklärung)衝破狹窄的欄位——這時需要 hyphens: auto(透過 Base.astro 已設定的 lang 屬性,為每種語言提供正確的斷字規則),再加上 overflow-wrap: break-word 作為備援方案;起始模板的 global.css 已將兩者都應用於 body 上。表格儲存格會關閉斷字功能(請參閱表格章節)。
  • 不要僅依賴 white-space: nowrap + text-overflow: ellipsis 來處理導覽連結或按鈕標籤——截斷導覽連結通常會造成不良的使用者體驗(訪客無法再辨識連結目的地)。這在截斷是可接受的取捨時(例如表格儲存格)是可行的,但不適用於導覽功能。
  • 使用實際的翻譯標籤進行驗證,而非英文佔位文字。 當網站部署了 astro-i18n-setup 的 LanguageSwitcher.astro 或任何雙語/多語言導覽時,請在 360/768/1280 解析度下(使用 preview_resize)檢查每種語言實際部署的文案佈局,而不僅僅是英文佔位文字。

表格

所有表格共用一種樣式;頁面上不會有針對表格的佈局 CSS。該樣式存在於起始模板的 src/styles/tables.css 中(由 Base.astro 在 global.css 之後匯入),而 tests/tables.spec.ts 會對其進行檢查。在此章節建立之前製作的網站,需要先複製 tables.css,在其版面中加入匯入行,然後移除每個頁面自己的表格 CSS。

有兩種表格類型,根據儲存格內容區分:

  • stack(句子):寬度超過 40rem 時為表格;低於此寬度時,每一行會堆疊顯示,行標題作為標題,每個儲存格在其欄位名稱下方。四欄的文字無法在 320px 內共享空間。
  • figures(短數字,在數字儲存格上加上 class="num"):在手機上仍保持表格形式,且必須能容納在 320px 內。如果無法容納,請改為 stack 類型;使用滾動條並非正確的解決方案。stack figures 一起使用則是以堆疊佈局顯示數字。

每張表格的標記:

<div class="table-wrap stack" role="region" aria-label="表格顯示的內容" tabindex="0">
  <table role="table">
    <thead role="rowgroup"><tr role="row">
      <th scope="col" role="columnheader">{cols[0]}</th><th scope="col" role="columnheader">{cols[1]}</th>
    </tr></thead>
    <tbody role="rowgroup">{rows.map((r) => (
      <tr role="row"><th scope="row" role="rowheader">{r.item}</th><td role="cell" data-label={cols[1]}>{r.text}</td></tr>
    ))}</tbody>
  </table>
</div>
  • 將欄位名稱撰寫一次,放在一個清單中,並將其用於表頭和每個 data-label:堆疊儲存格的標籤必須等於其欄位表頭,測試會比較兩者。figures 表格不需要每個儲存格的角色,也不需要 data-label。
  • 堆疊表格不再是 display: table。角色是對瀏覽器在版面變更時可能失去表格的備援方案;並不會檢查它們在該情況下是否能正常運作。在 Chromium 中,曾經對一個真實表格進行過測量,無障礙樹在沒有這些角色的情況下仍保留了表格結構。
  • 在一個儲存格中獨立存在的連結上使用 class="tap",可使其在手機上成為 44px 的觸控目標。nowrap 可將短值(例如 1, 3, 6)保持在同一行。long-head(與 stack 一起使用)會在行標題是句子時加寬第一欄。
  • 表格儲存格中的單字不會斷字。主體樣式的 hyphens: auto 可能會將狹窄的第一欄擠壓成片段(例如 "An-thropic"),因此區塊會在那裡設定 hyphens: manual。
  • 如果某個頁面的表格來自外部且無法攜帶上述標記,則應將其加入測試規格中的 TABLE_EXEMPT,並附上原因。PAGES 則保持完整:網站地圖和 llms.txt 檢查需要其中的每個有效路由。

tables.spec.ts 檢查的內容:每張表格都位於某一種類型的 .table-wrap 中,並具有其 region、label 和 tabindex;每個表頭儲存格都有 scope="col",每行第一個儲存格是 <th scope="row">,其餘為 <td>;堆疊表格具有其角色,且每個儲存格都有一個與表頭相等的 label;在 360 和 320px 螢幕寬度下,沒有頁面和表格會橫向捲動;在 641px 及以上的寬度下,堆疊表格會再次顯示為表格,顯示其表頭行,且沒有單字被中斷(這會捕捉到像 overflow-wrap: anywhere 這類讓欄位擠壓單字的規則);沒有儲存格具有 hyphens: auto。它還會在首頁上新增的測試用 fixture 上測試 CSS,並同時在兩種主題下使用 axe 進行無障礙檢測,因此即使沒有表格的網站也能證明該區塊是有效的。無頭 Chromium 不會進行斷字,因此斷字保護會讀取計算後的樣式,而非版面。Safari 和 VoiceOver 則不在檢查範圍內。

電子郵件混淆(對爬蟲隱藏地址)

切勿在 HTML 原始碼中放置純文字電子郵件或 mailto:your@addr——爬蟲會在數小時內將其擷取用於發送垃圾郵件。請透過 EmailLink.astro 元件(位於 new-website 技能的 templates/astro/src/components/EmailLink.astro,以及其 lib/obfuscate.ts 輔助程式)來渲染所有地址:地址在建置時會反轉並進行 base64 編碼,然後在瀏覽器中重新組合,因此提供的 HTML 中不包含任何可讀取的地址。不使用 JavaScript 的訪客會看到一個仍可使用的 "name [at] domain [dot] com" 提示。

<EmailLink address="[email protected]" subject="專案諮詢" text="寄信給我們" />

規則:建置後的 HTML 中零個原始 mailto: 連結和零個字面 @ 地址——website-qa 會檢查此項。任何不希望被擷取的電話號碼也適用相同概念。

品牌代碼

將 BRAND.md 的色板對應到代碼區塊中,並保持它們同步。定義:品牌色(固定),以及每個主題的 heading/ink/muted/accent/link/line/bg/bg-soft/surface。強調色和連結顏色必須在兩種主題的背景下都通過 AA 標準,這也是為什麼每個主題都有自己的色值。可選的 website-brand-kit 會進行帶檢查的對應程序:它會讀取 BRAND.md 的表格,將每個文字顏色在兩種主題的每個背景上保持在 4.5:1 的對比度,並將這些值寫入 global.css 的所有三個顏色區塊(淺色、深色,以及給沒有 JavaScript 訪客的深色區塊)。若手動操作,請同時修改這三個區塊。

完成標準

BRAND.md 已填寫完成且與代碼區塊一致;圖片為 WebP 格式、尺寸正確、延遲/積極載入設定正確、具有替代文字;無障礙測試(淺色+深色)通過;版面在 360/768/1280 解析度下保持穩定無位移;每張表格都是 stack 或 figures 類型,且 tables.spec.ts 測試通過。效能數據(FCP/LCP)已在 website-qa 中驗證。版面也需在所有部署語言的實際(非佔位)文案下,於 360/768/1280 解析度下保持穩定,而不僅僅是預設語系。

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

相關技能