테마
색은 CSS 변수로
HTML 화면의 테마는 웹에서와 같습니다. 사용자 정의 속성, prefers-color-scheme 미디어
쿼리, 그리고 사용자가 시스템 설정을 덮어쓸 때의 클래스입니다. 이 크레이트가 그것을 대신하는 것은
없으므로, 브라우저용으로 쓴 스타일시트의 테마가 그대로 남습니다.
사용자 정의 속성
samples/theme 은 모든 색을 var() 로 씁니다. 밝은 세트가 기본이고,
prefers-color-scheme: dark 아래에서는 어두운 세트가 적용되며, 앱 루트의 클래스가 둘
다를 이깁니다.
:root, .app.light {
--bg: #ffffff;
--surface: #f3f4f6;
--text: #111827;
--accent: #2563eb;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #111827;
--surface: #1f2937;
--text: #f9fafb;
--accent: #60a5fa;
}
}
.app.dark {
--bg: #111827;
--surface: #1f2937;
--text: #f9fafb;
--accent: #60a5fa;
}
.app { height: 100%; padding: 24px; background-color: var(--bg); color: var(--text); }
밝은 테마와 어두운 테마
HtmlConfig::color_scheme 이 prefers-color-scheme 에 답합니다. 따로 정하지
않으면 ColorScheme::Light 입니다.
let dom = HtmlDom::with_config(
theme::app,
HtmlConfig {
stylesheets: vec![theme::STYLE.to_string()],
color_scheme: ColorScheme::Dark,
..HtmlConfig::default()
},
);
앱에 클래스가 없으면 Dark 가 어두운 세트를 고릅니다. 테스트는 페이지의 모든 색을 두
세트와 비교합니다.
시스템 설정 덮어쓰기
토글 버튼은 루트 요소에 light 나 dark 를 붙입니다. 클래스만 바뀌므로 바뀌는
것은 색뿐입니다.
// None follows the system through the media query.
let mut theme = use_signal(|| None::<Theme>);
let class = match theme.cloned() {
None => "app",
Some(Theme::Light) => "app light",
Some(Theme::Dark) => "app dark",
};
rsx! {
div { id: "app", class: "{class}",
button {
id: "theme-toggle",
class: "toggle",
onclick: move |_| {
let next = match theme.cloned() {
Some(Theme::Dark) => Theme::Light,
_ => Theme::Dark,
};
theme.set(Some(next));
},
"Toggle theme"
}
}
}
테스트는 토글을 누르고 레이아웃 diff 를 확인합니다. 항목이 바뀌었고, 추가되거나 삭제된 것이 없고, 순서가 같고, 바뀐 항목은 모두 색만 달라졌습니다.
아직 없는 것
- 실행 중에 시스템 설정 따라가기. 계획 색
구성표는
HtmlDom을 만들 때 정해집니다. 시스템의 변화를 먼저 아는 것은 렌더러이므로, 렌더러가 HTML 화면을 그리게 되면 그 변화를 넘겨줍니다 (#43). - CSS 변수를 색 역할로. 계획 HTML 과 위젯이
섞인 화면에서 두 쪽이 한 테마를 따르도록 CSS 변수를 위젯의 색 역할에 잇습니다. 계획에는 그 자리가
이미 있습니다.
ColourResolver가 계산된 색을 그 색이 뜻하는 역할로 바꿀 수 있으므로, 테마가 바뀌어도 다시 배치할 필요가 없게 됩니다. 두 방식 섞기를 보십시오. - 움직이는 테마 전환. 계획
transition: background-color는 지금 재생되지 않습니다 (#46).