theme system

Hey, what would ya'll recommend as a good method to go about creating themes for a site? I had the idea of applying variables to html and having a data attribute toggle along with prefers-color-scheme (or lightdark()) e.g.
:root {
--bg-light: ...;
--bg-dark: ...;
}

@media (prefers-color-scheme: light) {
html {
--button-bg: var(--bg-light)
}
}

@media (prefers-color-scheme: dark) {
html {
--button-bg: var(--bg-dark)
}
}

html[data-light] {
--button-bg: var(--bg-light);
}

html[data-dark] {
--button-bg: var(--bg-dark);
}
:root {
--bg-light: ...;
--bg-dark: ...;
}

@media (prefers-color-scheme: light) {
html {
--button-bg: var(--bg-light)
}
}

@media (prefers-color-scheme: dark) {
html {
--button-bg: var(--bg-dark)
}
}

html[data-light] {
--button-bg: var(--bg-light);
}

html[data-dark] {
--button-bg: var(--bg-dark);
}
I'm not sure if this is a good maintainable way of doing something like this though. I'd appreciate any insight. Thanks in advance
22 Replies
b1mind
b1mindā€¢2mo ago
good way to go about it imo You could make the tokens a bit better maybe and not so specific.
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
i would do something better your implementation has a possible bug, where stuff is a mix of dark and light
b1mind
b1mindā€¢2mo ago
I typically override the root šŸ¤”
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
what you can do is something like this:
:root {
--theme: white;
@media (prefers-color-scheme: dark) {
--theme: black;
}

&[data-theme="dark"] {
--theme: black;
}
}

@container style(--theme: black) {
body, ::backdrop {
--bg: black;
}
}

@container style(--theme: white) {
body, ::backdrop {
--bg: #eee;
}
}

body {
background-color: var(--bg);
}
:root {
--theme: white;
@media (prefers-color-scheme: dark) {
--theme: black;
}

&[data-theme="dark"] {
--theme: black;
}
}

@container style(--theme: black) {
body, ::backdrop {
--bg: black;
}
}

@container style(--theme: white) {
body, ::backdrop {
--bg: #eee;
}
}

body {
background-color: var(--bg);
}
or something like that also, you only define the colors in 1 place i hope it works, because i didnt try it šŸ¤” doesnt seem to work, so, i will explore there, updated it here's a more refined example:
:root {
--theme: white;

@media (prefers-color-scheme: dark) {
--theme: black;
}

&[data-theme="dark"] {
--theme: black;
}

&[data-theme="light"] {
--theme: white;
}
}


body, ::backdrop {
@container style(--theme: white) {
--bg: #eee;
--color: #333;
}

@container style(--theme: black) {
--bg: black;
--color: white;
}
}


body {
color: var(--color);
background-color: var(--bg);
}
:root {
--theme: white;

@media (prefers-color-scheme: dark) {
--theme: black;
}

&[data-theme="dark"] {
--theme: black;
}

&[data-theme="light"] {
--theme: white;
}
}


body, ::backdrop {
@container style(--theme: white) {
--bg: #eee;
--color: #333;
}

@container style(--theme: black) {
--bg: black;
--color: white;
}
}


body {
color: var(--color);
background-color: var(--bg);
}
snxxwyy
snxxwyyOPā€¢2mo ago
Because of the prefers color scheme? Like if someone has prefers color scheme dark and the site is default to the data attribute light it could conflict?
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
yeah, and there's the risk that some stuff is light and other stuff is dark also, you're repeating yourself
snxxwyy
snxxwyyOPā€¢2mo ago
How so?
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
@media (prefers-color-scheme: light) {
html {
--button-bg: var(--bg-light)
}
}

html[data-light] {
--button-bg: var(--bg-light);
}
@media (prefers-color-scheme: light) {
html {
--button-bg: var(--bg-light)
}
}

html[data-light] {
--button-bg: var(--bg-light);
}
you're doing the same work twice
snxxwyy
snxxwyyOPā€¢2mo ago
oh i see. i was thinking that way because one is the browser preference and the other is a toggle switch
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
this works exactly the same: just don't add the data-theme attribute and you don't repeat yourself and when you add the data attribute, it respects the attribute and it's easier to extend as well by the way, you have to replicate the styles to the ::backdrop element, if you use dialogs or videos ::backdrop is special - it doesn't inherit any properties
snxxwyy
snxxwyyOPā€¢2mo ago
oh okay i see. in your solution, what are the positives of the @container style() declarations? couldn't you do this? or is that unecessary repetition?
:root {
--bg: #eee;
--color: #333;

@media (prefers-color-scheme: dark) {
--bg: black;
--color: white;
}

&[data-theme="dark"] {
--bg: black;
--color: white;
}

&[data-theme="light"] {
--bg: #eee;
--color: #333;
}
}
:root {
--bg: #eee;
--color: #333;

@media (prefers-color-scheme: dark) {
--bg: black;
--color: white;
}

&[data-theme="dark"] {
--bg: black;
--color: white;
}

&[data-theme="light"] {
--bg: #eee;
--color: #333;
}
}
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
the positives: you dont repeat yourself by not repeating yourself, you also don't make any mistakes imagine you have 30 variables now, you need to update the same value twice per theme
clevermissfox
clevermissfoxā€¢2mo ago
So are you setting the html El as a container-type for this?
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
im just doing this nothing else that's the entire css
clevermissfox
clevermissfoxā€¢2mo ago
So if no container is defined, @container refers to the html
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
yes, the body and ::backdrop
Doksuri
Doksuriā€¢2mo ago
can you explain theses lines ? @container style(--theme: white) { i don't quite get it... even if i kind of understand what it does
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
it's a container query that checks the value of the custom property, and compares to the value given think of this as an if that checks if --theme is equal to white
Doksuri
Doksuriā€¢2mo ago
i can't find the mdn doc of style() function -_- https://caniuse.com/css-container-queries-style is this it ?
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
yes it is you can also just google "query containers with style" and it should show the mdn page
į¼”ĻĻ‰Ļ‚
į¼”ĻĻ‰Ļ‚ā€¢2mo ago
you're welcome
Want results from more Discord servers?
Add your server