Theming system with SASS

Hello everyone, I'm a newbie in frontend stuff. To be fair I've never worked for the web, I'm more of a backend guy. A few years ago though I discovered I kinda like designing UIs. I have a desktop project for which I decided to use SASS to style my components. I studied and took some notes on SASS, I'm using the 7-1 pattern My main goal is to port Material Design 3 to the desktop. However, I was thinking, what if in the future I want to use other designs, like Nord, Catppuccin, Flat, Fluent, etc... Let me express my doubts through an example. Let's consider a button. Material Design makes buttons round, there are many variants, uses ripples and so on... On the other end other designs make the button a rounded rectangle, do not use ripples, some may not rely on background color for the interaction states but rather the border. In simpler terms, each design may define a completely different styling structure. Do you think it's possible to implement a system, without duplicating the components scss files for each theme? How would you do it? My current system uses maps to define the styles for each theme, and there is a mixin for each design system and variant of the component, all in the same component's file, if you want to see the code let me know, there is actually a lot going on
4 Replies
Kevin Powell
Kevin Powell5mo ago
Some theming is very possible. Turning on/off ripples and more starts pushing how far you might want to go with theming though... But, as an example, you could do:
$button-styles: (
"variant-1": (
"border-radius": 0,
"background-color": red,
"color": blue,
"background-on-hover": blue,
"color-on-hover": red
),
"variant-2": (
"border-radius": 1rem,
"background-color": black,
"color": white,
"background-on-hover": white,
"color-on-hover": black
)
)
$button-styles: (
"variant-1": (
"border-radius": 0,
"background-color": red,
"color": blue,
"background-on-hover": blue,
"color-on-hover": red
),
"variant-2": (
"border-radius": 1rem,
"background-color": black,
"color": white,
"background-on-hover": white,
"color-on-hover": black
)
)
You could have variant- be the theme names, and then use loops to do most of the styling... Something like:
$active-theme: $variant-1;

.button {
color: map.get($button-styles, $active-theme, color);
}
$active-theme: $variant-1;

.button {
color: map.get($button-styles, $active-theme, color);
}
If I was doing that, I'd probably make a custom function so I wouldn't have to use map.get() everywhere... I use a lot of tokens in my work, as generally each project has it's own theme, so I just update things project to project, and this would probably take a long time to set up properly, but it could be an option if you really want to dive into it. You can see this working here if you want to poke around with it. https://sass-lang.com/playground/#eJytUctqwzAQvOsrFhNKAlKoe1Qv+RXJ3saislX0cCkh/961nAbZISWU3szM7HhmVNeHFBCqoEKQvfqoXhnb6BSjG0SIXxaDhC0DqEbljRqiqKsZIEg736IXXrUmBYKf+QVXzfvRuzS0onHWeaI8thfyB9E24a2e/tq5EVeCfFNyZEfMjpfBXu4Hqz3297NpS9gq3Wdn4u/xSsVNvmw5JWS7aU/VRDOiiB32KOG6JFH7eWo4kTi7SKBH2B8xbpevwGHhwmc1uQOsKz1ssT6c3crtHrcqr6bOAE8yr8Hp4801KYjRBKMt5q5/antdOAf9n+ILyzM7fwOjwPse
Alex
AlexOP5mo ago
Hello Kevin, thanks for answering I'm already using maps and loops but in a more intricate way. Here's how my system works: Sass Playground What I posted is only a portion of it, two things to notice mainly: 1) Properties make no sense. That's because my framework actually uses a subset of CSS (W3C CSS version 2.1 with some additions from current work on version 3.), so I have a function that translates keys in the maps to the correct properties (e.g., bg-color is background in CSS but -fx-background-color in my framework) 2) The framework allows defining custom pseudo states, like with-icon-left 3) I did not post some functions as they are irrelevant. For example: ApplyMDStateLayer just takes the color from the scheme and adjusts its opacity according to the needed state. GetStateLayer retrieves the opacity value from a map for the desired state. As you can see in my code, a button can have many variants (at least in Material Design 3), which means that making a single map for every theme and every variant may make things a bit messy Although, I could and probably should separate every variant in another scss file. (e.g., _buttons_filled.scss, _buttons_filled_tonal.scss,...)
P.S: the $base-styles map contains only properties relative to layout, shape, size, position. Colors are 99% sure to change depending on the theme, while the others…well I don't know to be honest, so I consider this organization still WIP. Thing is, I'd really like for my project to support multiple themes one day, and give my user base choice. But I don't know why, this much complexity feels so wrong 😅
Sass: Playground
Syntactically Awesome Style Sheets
Kevin Powell
Kevin Powell5mo ago
Haha, put my simple example to shame there 😅
Thing is, I'd really like for my project to support multiple themes one day, and give my user base choice. But I don't know why, this much complexity feels so wrong 😅
It really depends on how far you want to go with it. Changing colors, like you said, is pretty simple. That's the easy one to change. If you want completely different themes, you can do it, but you're basically recreating each one within your system. You have to decide if that's worth it, or if you just want simpler changes (border radius on/off, for example, or even maybe steps, so "off", "small", "large" or something like that). You could find a middle ground if you wanted, where you're only exposing certain things to be changed. It could still provide pretty robust theming that way, without having to completely re-invent things for each one.
ἔρως
ἔρως5mo ago
with configuration files and a little bit of "magic", you can (somewhat) easily make pretty complex themes
Want results from more Discord servers?
Add your server