ダークモード
現状の使い方(実装済み・JSでの切り替え)
Section titled “現状の使い方(実装済み・JSでの切り替え)”import { ThemeProvider, defaultTheme, darkTheme } from "@hirasaki1985/web-ui";
const App = () => ( <ThemeProvider themes={{ light: defaultTheme, dark: darkTheme }} colorScheme="dark"> {/* ... */} </ThemeProvider>);ThemeProvider に themes(ライト/ダーク2つのテーマ)と colorScheme("light" | "dark")を渡すと、配下のすべてのコンポーネントが colorScheme に応じたテーマで描画されます。colorScheme はReactの状態として自分で管理してください(OS設定の検知やユーザー切り替えUIはライブラリの外側の責務です)。
darkTheme は defaultTheme と同じPrimitiveパレットを共有し、Semantic/Componentだけをダーク向けに再導出したものです(buildDarkSemanticColors / buildDarkComponentColors)。ニュートラル(gray)を反転しつつ、本文テキストの対象ロールは両モードともWCAG AA(4.5:1)を満たすステップに調整しています。アイコン/ボーダーは用途によって基準未達の値も含むため、実際の値と比率は 色 を参照してください。
この仕組みは現在styled-componentsのReact Context経由でのみ動作します。CSSカスタムプロパティやHTML属性は使っていません。
計画中:CSS属性でのダーク切り替え
Section titled “計画中:CSS属性でのダーク切り替え”CSSカスタムプロパティによる配布を追加する計画があり、そこでは属性ベースの切り替えを採用します。
/* 配布CSS(計画中のイメージ) */:root { --wui-text-primary: var(--wui-color-gray-900); }[data-wui-color-scheme="light"] { --wui-text-primary: var(--wui-color-gray-900); }
@media (prefers-color-scheme: dark) { :root:not([data-wui-color-scheme="light"]) { --wui-text-primary: var(--wui-color-gray-50); }}[data-wui-color-scheme="dark"] { --wui-text-primary: var(--wui-color-gray-50); }| やりたいこと | 書き方 |
|---|---|
| OS設定に追従 | 属性を付けない |
| 明示的にダーク | <html data-wui-color-scheme="dark"> |
| 一部だけダーク | <aside data-wui-color-scheme="dark"> |
優先順位: ① 要素自身の明示属性 → ② 祖先の明示属性 → ③ OSの prefers-color-scheme → ④ 既定のlight。CSSの詳細度と継承によってこの順序になります。
属性方式を選んだ理由: :root にJSで色を注入する方式だと、SSRの初回HTMLが必ずライトになり、ハイドレーション後に色がチラつきます。属性方式なら配布CSSに両方の定義があるため、サーバーが返すHTMLの時点で正しい色になります。
useTheme() との整合
Section titled “useTheme() との整合”CSS属性を追加しても、ThemeProvider の themes / colorScheme というAPI自体は維持される計画です(useTheme() を使うコンポーネントが引き続き動くようにするため)。実装後は ThemeProvider が次の2つを同時に行います。
colorSchemeに応じてdata-wui-color-scheme属性をDOMへ出す → CSS側が切り替わる- 同じ
colorSchemeの値でReact Contextにテーマを流す →useTheme()の戻り値と一致する
出所を ThemeProvider 1箇所にすることで、「CSSはダークなのに useTheme() がライトの実値を返す」というズレが起きない設計にする計画です。ThemeProvider を経由せず <html> へ直接属性を付けた場合、useTheme() は追従しません(CSSのみが対象になります)。
SSRでの扱い
Section titled “SSRでの扱い”- OS設定への追従だけでよい場合: 属性を出す処理はハイドレーション後に実行される想定のため、属性なしの初回HTMLでも
prefers-color-schemeのメディアクエリでOS設定通りの色になります。何もする必要はありません。 - ユーザーが画面で選んだ設定を使いたい場合: 保存先(cookie / DB / URL等)はアプリ側の都合のため、ライブラリはその保存・読み出しを提供しません。利用側がcookie等から読んで属性をSSR時に出力します。
// 利用側の実装イメージ(Next.js App Router の例)export default async function Layout({ children }: { children: React.ReactNode }) { const scheme = (await cookies()).get("color-scheme")?.value; return <html data-wui-color-scheme={scheme}>{children}</html>;}localStorage を読むインライン<script>を注入する方式(一部のライブラリで見られる方式)は、Content-Security-Policyでinline scriptを禁じている環境で動かないため採用しない方針です。