Linyao Design System
主題
Linyao Design System 以語意變數定義主題。所有主題共用相同的元件 CSS;亮色、深色或自訂主題只重新指定角色變數。
載入樣式
在應用程式入口匯入一次:
import "@linyao.tw/ui/styles.css";
不得從 @linyao.tw/ui/dist/**、src/** 或內部 CSS 路徑匯入。公開樣式入口只有兩個:必要的 @linyao.tw/ui/styles.css,以及可選的 @linyao.tw/ui/fonts.css。
字型
styles.css 不載入任何遠端資源。品牌字型是獨立的可選入口:
import "@linyao.tw/ui/fonts.css"; // 選用
import "@linyao.tw/ui/styles.css";
fonts.css 會向 font.emtech.cc 與 fonts.gstatic.com 發出三個跨來源請求。正式環境建議自行代管相同字型,並覆寫 --font-family-sans、--font-family-serif 與 --font-family-mono 指向自己的 @font-face;設計變數本身已帶有系統字型備援,未載入 fonts.css 時元件仍可正常呈現。
不匯入 fonts.css 的理由通常是:Content Security Policy 未允許這兩個網域、離線或內網環境無法連線,或需要避免 CSS @import 造成的串行阻塞。
選擇主題
亮色是 :root 預設,也可明確指定:
<html data-lyds-theme="light"></html>
深色:
<html data-lyds-theme="dark"></html>
主題也可套在子樹:
<main data-lyds-theme="light">
<Preview />
<aside data-lyds-theme="dark">
<DarkPreview />
</aside>
</main>
一般應用程式應將主題設在文件根元素。Select、Combobox、Menu、Tooltip、Dialog、DatePicker 等浮層元件預設透過 portal 呈現在 body,會依 portal 目的節點的祖先元素取得設計變數。若主題只套在子樹,portal 容器也必須位於相同主題範圍。
每個主題範圍同時設定對應的 color-scheme,使瀏覽器原生控制項與 Linyao Design System 表面一致。
主題狀態
主題狀態由應用程式管理。Linyao Design System 不讀取系統偏好、不寫入 localStorage,也不建立全域 React context。
type LydsTheme = "light" | "dark";
export function AppTheme({ theme, children }: React.PropsWithChildren<{ theme: LydsTheme }>) {
document.documentElement.dataset.lydsTheme = theme;
return children;
}
需要跟隨系統時,應用程式可使用 matchMedia("(prefers-color-scheme: dark)")。需要保存設定時,由應用程式選擇 cookie、伺服器設定或 localStorage。
首次繪製
SSR 的伺服器標記與用戶端第一次 render 必須使用相同主題。若只能在瀏覽器決定,可由應用程式在 hydration 前設定 document.documentElement.dataset.lydsTheme。Linyao Design System 不注入此程式,因為儲存方式、CSP、nonce 與系統偏好都屬於產品設定。
淺色主題
Limestone
├─ Background/Main 暖白主背景
├─ Background/Secondary 清單與相鄰表面
├─ Background/Elevated 浮動表面
├─ Background/Inset 群組控制項表面
└─ Background/Sunken 次要表面
Charcoal
├─ Text/Title 與 Text/Main
├─ 圖示
└─ 低對比分隔線
Vermilion
├─ primary action
├─ 選取/勾選
└─ 必要的狀態強調
表面層級主要透過明度、選取底板與結構性分隔線表達。陰影只用於浮動元件或浮層元件。Vermilion 上的文字使用 OnAccent 語意值。
深色主題
Background/Main約為oklch(0.18 0.008 75)的暖色近黑。Background/Secondary與Background/Elevated逐層提高明度。Background/Inset/Sunken保留群組層級,不使用單一純黑背景。Text/Main使用 Limestone/暖色中性色系。- Vermilion 保留主要操作與選取角色,不加入 neon glow。
- 細線與陰影依深色主題重新指定,不直接反轉亮色主題值。
深色色盤、語意設定與動態效果是 Linyao Design System 的設計,不是 Modulor 公開 Figma 元件庫的原始內容。
自訂主題
覆寫語意變數
使用 class 或 data attribute 覆寫語意角色:
.operations-theme {
--background-main: oklch(88% 0.018 82);
--background-secondary: oklch(92% 0.014 82);
--text-main: oklch(35% 0.01 82);
--control-primary: var(--palette-signal-600);
--control-primary-hover: var(--palette-signal-700);
--control-primary-pressed: var(--palette-signal-800);
--control-on-primary: var(--palette-warm-25);
--focus-ring: oklch(48% 0.17 32);
}
<section className="operations-theme" data-lyds-theme="light">
<AccountSettings />
</section>
完整自訂主題必須覆寫語意角色,不能只修改 --palette-vermilion。元件不直接使用色盤變數。
使用語意角色
建議:
.billing-surface {
--control-primary: var(--billing-action);
}
不建議:
.billing-surface .lyds-button[data-variant="primary"] {
background: #e04010;
}
直接覆寫 .lyds-* 會略過 hover、按下、停用、深色主題與未來內部變更。若現有語意角色無法完成合理的自訂,應先提出設計變數調整,不要分支修改元件 CSS。
版面調整
className 與 style 用於應用程式控制的位置、寬度與 grid/flex 關係:
<DatePicker className="checkout-delivery-date" label="交付日期" />
.checkout-delivery-date {
inline-size: min(100%, 24rem);
}
不要以 style 傳入元件原始色值。需要從 React 動態傳入設計變數時,使用 CSS custom property 與可檢查的型別包裝。
主題驗證
每個主題都必須檢查:
- 內文、標題、次要、停用與連結文字;
- primary、secondary、quiet、danger 操作;
- 輸入元件預設/hover/焦點/無效/唯讀/停用;
- 選取/勾選控制項;
- popup、dialog、drawer、bottom sheet、backdrop;
- Toast/狀態表面;
- 日期選取/範圍/今天/不可用狀態;
focus-visible、鍵盤順序與焦點返回;- 繁體中文與英文混合的長文字;
- 200% zoom 與窄螢幕;
prefers-reduced-motion: reduce;- 產品需要列印時的 print colors。
修改主題不應造成版面位移。語意值改變時,元件尺寸、互動目標與文字換行應保持一致。
對比責任
內建主題以 WCAG 2.2 AA 為目標。使用者覆寫主題後,必須重新驗證:
- 前景色與合成後背景;
- 焦點指示器與控制項/相鄰表面;
- 非文字控制項邊界;
- hover/按下/選取狀態;
- 停用狀態的可讀性。
品牌原色不保證符合對比。Limestone、Charcoal 與 white 都不適合直接作為 Vermilion 上的一般尺寸文字。品牌強調表面應使用 --text-on-accent;需要近白前景的主要控制項,應同時使用較深的 --control-primary 與 --control-on-primary。