Issue
Hi All!
I'm currently working on a theming feature for a CSS Framework and have run into some issues that I'm hoping you might be able to help out with.
I have created a SASS Map called $themes
, which contains colors for different themes. I copy-pasted some code from a medium article(who doesn't) and boom my theming works!
But...
This:
@include themify($themes) {
.btn {
color: themed('blue');
}
}
on. every. component. is sloppier code than what I deem maintainable across the copious amounts of styling I'll be doing.
So...
My Goal
I'd like to do something super hacky and awesome like this:
@include themify($themes) {
$blue: themed(blue);
}
I want to theme the variables so all I have to do is add $blue
and not a lot of calling mixins and unnecessary mumbo jumbo.
If I could get something like this to work it would look something like this:
.btn {
background: $blue;
}
All of the theming would be taken care of beforehand!
But of course it's never that easy because it doesn't work... It would be a godsend if one of you awesome sass
magicians could pull some magic with this, I will include you in the source code of awesome contributors.
The Code
The $themes
sass-map:
$themes: (
light: (
'blue': #0079FF
),
dark: (
'blue': #0A84FF
)
);
The copypasta mixin from this awesome Medium Article:
@mixin themify($themes) {
@each $theme, $map in $themes {
.theme-#{$theme} {
$theme-map: () !global;
@each $key, $submap in $map {
$value: map-get(map-get($themes, $theme), '#{$key}');
$theme-map: map-merge($theme-map, ($key: $value)) !global;
}
@content;
$theme-map: null !global;
}
}
}
@function themed($key) {
@return map-get($theme-map, $key);
}
Any suggestions on how to accomplish this would be 100% appreciated. Appreciated enough to add you into the source code as an awesome contributor.
Thanks in Advance!
Solution
Sass does not allow you to create variables on the fly – why you need to manually declare the variables in the global scope.
$themes: (
light: (
'text': dodgerblue,
'back': whitesmoke
),
dark: (
'text': white,
'back': darkviolet
)
);
@mixin themify($themes) {
@each $theme, $map in $themes {
.theme-#{$theme} {
$theme-map: () !global;
@each $key, $submap in $map {
$value: map-get(map-get($themes, $theme), '#{$key}');
$theme-map: map-merge($theme-map, ($key: $value)) !global;
}
@content;
$theme-map: null !global;
}
}
}
@function themed($key) {
@return map-get($theme-map, $key);
}
@mixin themed {
@include themify($themes){
$text: themed('text') !global;
$back: themed('back') !global;
@content;
}
}
@include themed {
div {
background: $back;
color: $text;
border: 1px solid;
}
}
The problem about this approach (apart from being tedious to maintain) is that it will bloat your CSS with things that are not related to theming – in the example above border will be repeated.
.theme-light div {
background: whitesmoke;
color: dodgerblue;
border: 1px solid; // <=
}
.theme-dark div {
background: darkviolet;
color: white;
border: 1px solid; // <=
}
While I think it is possible to create a setup that scopes each theme to it's own individual stylesheet (e.g. light.css and dark.css) I think you should consider using CSS variables to handle this
$themes: (
light: (
'text': dodgerblue,
'back': whitesmoke
),
dark: (
'text': white,
'back': darkviolet
)
);
@each $name, $map in $themes {
.theme-#{$name} {
@each $key, $value in $map {
--#{$key}: #{$value};
}
}
}
div {
background: var(--back);
color: var(--text);
border: 1px solid;
}
CSS output
.theme-light {
--text: dodgerblue;
--back: whitesmoke;
}
.theme-dark {
--text: white;
--back: darkviolet;
}
div {
background: var(--back);
color: var(--text);
border: 1px solid;
}
Note! You only need to add the theme class to e.g. the body tag and the nested elements will inherit the values :)
Answered By - Jakob E
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.