Color mode

Theme Root と Attributes

このページは テーマ作成の詳細 の一部で、Theme Root と Theme 固有 Attribute を扱います。

15. Theme Root

Theme CSS は Document 全体へ無条件に適用しません。

基本 Selector は、

css
:is(:root, .rb-theme-root)
[data-theme-name="<name>"]

です。

<name> には Theme の Identity Name が入ります。

組み込み Theme では、たとえば、

text
riebeckite
minimal
gruvbox
sakura
tokyonight
rerurate

があります。

16. Theme Root が必要な理由

通常の Site では Application が <html> に Theme 名を付けます。

html
<html data-theme-name="minimal">

この場合は :root が Theme Root になります。

一方、Theme Gallery では、

html
<div
  class="rb-theme-root"
  data-theme-name="minimal"
>
  ...
</div>
 
<div
  class="rb-theme-root"
  data-theme-name="gruvbox"
>
  ...
</div>

のように、同じ Document 内で複数 Theme を表示できます。

Diagram source
text
flowchart TD
    CSS["同じTheme CSS"]
 
    CSS --> Site["実Site<br/>:root"]
    CSS --> PreviewA["Preview<br/>.rb-theme-root"]
    CSS --> PreviewB["別Theme Preview<br/>.rb-theme-root"]

そのため Theme CSS を裸の、

css
:root {
  /* ... */
}

として定義しないでください。

17. Theme Rule の Scope

Color Mode、Typography、Theme Option、Element Rule も同じ Theme Root に閉じ込めます。

css
/* Light */
:is(:root, .rb-theme-root)
[data-theme-name="<name>"] {
  /* ... */
}
 
/* Dark */
:is(:root, .rb-theme-root)
[data-theme-name="<name>"]
[data-theme="dark"] {
  /* ... */
}
 
/* System */
@media (prefers-color-scheme: dark) {
  :is(:root, .rb-theme-root)
  [data-theme-name="<name>"]
  :not([data-theme]) {
    /* ... */
  }
}
 
/* Typography */
:is(:root, .rb-theme-root)
[data-theme-name="<name>"]
[data-typography="serif"] {
  /* ... */
}
 
/* Theme Option */
:is(:root, .rb-theme-root)
[data-theme-name="<name>"]
[data-example-option="on"] {
  /* ... */
}
 
/* Elements */
:is(:root, .rb-theme-root)
[data-theme-name="<name>"]
:focus-visible {
  /* ... */
}

data-theme-name は Application が出力します。

Preview では .rb-theme-root と同じ Theme Name を指定します。

18. Theme 固有 Attributes

Theme 固有 Option を CSS へ渡したい場合は、安全な data-* Attribute を利用します。

ts
return defineTheme({
  name: "newspaper",
 
  attributes: {
    "data-newspaper-density":
      "compact",
  },
});

CSS では、

css
:is(:root, .rb-theme-root)
[data-theme-name="newspaper"]
[data-newspaper-density="compact"] {
  /* ... */
}

のように利用できます。

Theme API から、

text
class
style
id
lang

などを自由に変更する設計にはしません。

Framework が所有する Attribute と Theme 固有 Attribute を分離してください。

ThemeRoot と themeRootAttributes

Framework は ThemeRoot という UI primitive を提供し、<html> 要素への theme 属性の付与を担当します。

tsx
import { ThemeRoot } from "@riebeckite/honox/ui";
 
<ThemeRoot
  theme={config.theme}
  lang={c.get("htmlLanguage") ?? config.site.locale}
>
  {children}
</ThemeRoot>

ThemeRoot は次のように <html> 要素を描画します。

html
<html
  lang="ja"
  data-theme-name="minimal"
  data-theme="dark"
  data-typography="system"
  data-article-layout="article"
>

Framework は themeRootAttributes(theme) を使って、theme の attributes に加え、以下の予約属性を <html> へ出力します。

  • data-theme: Color Mode の状態 ("light" / "dark" / 未設定の場合は削除)
  • data-theme-name: Theme の識別子
  • data-typography: Typography Preset の値
  • data-article-layout: Article Layout Preset の値

独自の <html> 属性を追加したい場合は、ThemeRoot の代わりに themeRootAttributes を直接使えます。

tsx
import { themeRootAttributes } from "@riebeckite/honox/ui";
 
<html
  lang={c.get("htmlLanguage") ?? config.site.locale}
  {...themeRootAttributes(config.theme)}
  data-custom-attr="..."
>
  ...
</html>

ただし、Framework が予約する data-theme, data-theme-name, data-typography, data-article-layout は theme 側の attributes では上書きされません。

Plugin や Theme が独自に themeAttributes() を実装していた場合は、Framework が提供する ThemeRoot / themeRootAttributes() への移行を検討してください。Framework が所有する attribute namespace と Theme 固有の namespace を明確に分離できます。

History

1 changesCollapseExpand
1 + ---
2 + title: Theme Root と Attributes
3 + sidebar:
4 + label: Theme Root と Attributes
5 + order: 40
6 + ---
7 + # Theme Root と Attributes
8 +
9 + このページは [テーマ作成の詳細](../theme-system.ja.md) の一部で、Theme Root と Theme 固有 Attribute を扱います。
10 +
11 + ## 15. Theme Root
12 +
13 + Theme CSS は Document 全体へ無条件に適用しません。
14 +
15 + 基本 Selector は、
16 +
17 + ```css id="36j35i"
18 + :is(:root, .rb-theme-root)
19 + [data-theme-name="<name>"]
20 + ```
21 +
22 + です。
23 +
24 + `<name>` には Theme の Identity Name が入ります。
25 +
26 + 組み込み Theme では、たとえば、
27 +
28 + ```text id="l0yyse"
29 + riebeckite
30 + minimal
31 + gruvbox
32 + sakura
33 + tokyonight
34 + rerurate
35 + ```
36 +
37 + があります。
38 +
39 +
40 + ## 16. Theme Root が必要な理由
41 +
42 + 通常の Site では Application が `<html>` に Theme 名を付けます。
43 +
44 + ```html id="18amdy"
45 + <html data-theme-name="minimal">
46 + ```
47 +
48 + この場合は `:root` が Theme Root になります。
49 +
50 + 一方、Theme Gallery では、
51 +
52 + ```html id="3ynnb9"
53 + <div
54 + class="rb-theme-root"
55 + data-theme-name="minimal"
56 + >
57 + ...
58 + </div>
59 +
60 + <div
61 + class="rb-theme-root"
62 + data-theme-name="gruvbox"
63 + >
64 + ...
65 + </div>
66 + ```
67 +
68 + のように、同じ Document 内で複数 Theme を表示できます。
69 +
70 + ```mermaid id="5jjg45"
71 + flowchart TD
72 + CSS["同じTheme CSS"]
73 +
74 + CSS --> Site["実Site<br/>:root"]
75 + CSS --> PreviewA["Preview<br/>.rb-theme-root"]
76 + CSS --> PreviewB["別Theme Preview<br/>.rb-theme-root"]
77 + ```
78 +
79 + そのため Theme CSS を裸の、
80 +
81 + ```css id="69pszy"
82 + :root {
83 + /* ... */
84 + }
85 + ```
86 +
87 + として定義しないでください。
88 +
89 +
90 + ## 17. Theme Rule の Scope
91 +
92 + Color Mode、Typography、Theme Option、Element Rule も同じ Theme Root に閉じ込めます。
93 +
94 + ```css id="bsov79"
95 + /* Light */
96 + :is(:root, .rb-theme-root)
97 + [data-theme-name="<name>"] {
98 + /* ... */
99 + }
100 +
101 + /* Dark */
102 + :is(:root, .rb-theme-root)
103 + [data-theme-name="<name>"]
104 + [data-theme="dark"] {
105 + /* ... */
106 + }
107 +
108 + /* System */
109 + @media (prefers-color-scheme: dark) {
110 + :is(:root, .rb-theme-root)
111 + [data-theme-name="<name>"]
112 + :not([data-theme]) {
113 + /* ... */
114 + }
115 + }
116 +
117 + /* Typography */
118 + :is(:root, .rb-theme-root)
119 + [data-theme-name="<name>"]
120 + [data-typography="serif"] {
121 + /* ... */
122 + }
123 +
124 + /* Theme Option */
125 + :is(:root, .rb-theme-root)
126 + [data-theme-name="<name>"]
127 + [data-example-option="on"] {
128 + /* ... */
129 + }
130 +
131 + /* Elements */
132 + :is(:root, .rb-theme-root)
133 + [data-theme-name="<name>"]
134 + :focus-visible {
135 + /* ... */
136 + }
137 + ```
138 +
139 + `data-theme-name` は Application が出力します。
140 +
141 + Preview では `.rb-theme-root` と同じ Theme Name を指定します。
142 +
143 +
144 + ## 18. Theme 固有 Attributes
145 +
146 + Theme 固有 Option を CSS へ渡したい場合は、安全な `data-*` Attribute を利用します。
147 +
148 + ```ts id="ylx4jp"
149 + return defineTheme({
150 + name: "newspaper",
151 +
152 + attributes: {
153 + "data-newspaper-density":
154 + "compact",
155 + },
156 + });
157 + ```
158 +
159 + CSS では、
160 +
161 + ```css id="4evhcs"
162 + :is(:root, .rb-theme-root)
163 + [data-theme-name="newspaper"]
164 + [data-newspaper-density="compact"] {
165 + /* ... */
166 + }
167 + ```
168 +
169 + のように利用できます。
170 +
171 + Theme API から、
172 +
173 + ```text id="cn9sza"
174 + class
175 + style
176 + id
177 + lang
178 + ```
179 +
180 + などを自由に変更する設計にはしません。
181 +
182 + Framework が所有する Attribute と Theme 固有 Attribute を分離してください。
183 +
184 + ### ThemeRoot と themeRootAttributes
185 +
186 + Framework は `ThemeRoot` という UI primitive を提供し、`<html>` 要素への theme 属性の付与を担当します。
187 +
188 + ```tsx
189 + import { ThemeRoot } from "@riebeckite/honox/ui";
190 +
191 + <ThemeRoot
192 + theme={config.theme}
193 + lang={c.get("htmlLanguage") ?? config.site.locale}
194 + >
195 + {children}
196 + </ThemeRoot>
197 + ```
198 +
199 + `ThemeRoot` は次のように `<html>` 要素を描画します。
200 +
201 + ```html
202 + <html
203 + lang="ja"
204 + data-theme-name="minimal"
205 + data-theme="dark"
206 + data-typography="system"
207 + data-article-layout="article"
208 + >
209 + ```
210 +
211 + Framework は `themeRootAttributes(theme)` を使って、theme の `attributes` に加え、以下の予約属性を `<html>` へ出力します。
212 +
213 + - `data-theme`: Color Mode の状態 (`"light"` / `"dark"` / 未設定の場合は削除)
214 + - `data-theme-name`: Theme の識別子
215 + - `data-typography`: Typography Preset の値
216 + - `data-article-layout`: Article Layout Preset の値
217 +
218 + 独自の `<html>` 属性を追加したい場合は、`ThemeRoot` の代わりに `themeRootAttributes` を直接使えます。
219 +
220 + ```tsx
221 + import { themeRootAttributes } from "@riebeckite/honox/ui";
222 +
223 + <html
224 + lang={c.get("htmlLanguage") ?? config.site.locale}
225 + {...themeRootAttributes(config.theme)}
226 + data-custom-attr="..."
227 + >
228 + ...
229 + </html>
230 + ```
231 +
232 + ただし、Framework が予約する `data-theme`, `data-theme-name`, `data-typography`, `data-article-layout` は theme 側の `attributes` では上書きされません。
233 +
234 + Plugin や Theme が独自に `themeAttributes()` を実装していた場合は、Framework が提供する `ThemeRoot` / `themeRootAttributes()` への移行を検討してください。Framework が所有する attribute namespace と Theme 固有の namespace を明確に分離できます。
235 +