i-Willink
ドキュメントメニュー

ダークモード

willink DS のダークモードは data-theme 属性の契約です(.dark class ではありません)。data-theme は 未指定 / "dark" / "light" の 3 状態を取り、 semantic role が cascade 上でフリップします(ADR-0013)。

data-theme 契約

tsx
<!-- 未指定: OS 設定に追従(auto) -->
<html>…</html>

<!-- 強制 dark(OS を上書き) -->
<html data-theme="dark">…</html>

<!-- 強制 light(OS を opt-out) -->
<html data-theme="light">…</html>

未指定のとき DS は OS 設定(prefers-color-scheme)に 自動追従します。明示的に data-theme="dark" を付けると常に dark、data-theme="light" は OS が dark でも light に固定します(OS の opt-out)。 auto の挙動は次の media query で実現されています。

css
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* 21 の semantic role がここで dark にフリップ */
  }
}

フリップする role(代表例)

willink.dark 拡張で 21 の semantic role が dark にフリップします — core(bg / fg / muted / border)、 text-emphasis ladder(fg-strong / fg-emphasis / fg-secondary / fg-subtle / fg-faint)、 surfaces(surface-subtle / surface-muted / track / surface-inverted / surface-inverted-fg)、 brand state(brand-hover / brand-active / brand-soft / brand-soft-fg)、 feedback(success / warning / danger)。代表的な値の対応は以下の 通りです(gradient endpoint も dark で調整されますが、これは preset 内部変数で semantic role ではありません)。

rolelightdark
bg#ffffffneutral-950
fgneutral-900neutral-50
borderneutral-200neutral-800
brand-hoverbrand-700brand-500
brand-softbrand-100brand-950

一方で mode-invariant(フリップしない)なものもあります — numeric scale (neutral / brand の 50〜950)、brand(= brand-600)、brand-fg(#ffffff)、ring(= brand)、accent-cyan / accent-pink。 numeric step を直接使う consumer は dark コントラストを自分で担保してください。

dark: variant は不要

フリップは :root の cascade で起きるため、コンポーネント側に Tailwind の dark: variant は 一切不要です。data-theme を切り替えるだけで、 再 render なしにランタイムで再テーマ化されます。

非 Tailwind consumer

Tailwind を使わない consumer は @willink-labs/css-tokens の dark バンドルを追加します。これは上記と同じフリップを CSS 変数の代入として 運びます。

css
/* Tailwind を使わない consumer (WordPress / Astro / Vue / plain CSS) */
@import "@willink-labs/css-tokens/tokens.css";
@import "@willink-labs/css-tokens/tokens.dark.css";

次は ブランドとテーマ で単一ノブ(--color-brand) の仕組みを確認する。