I have this in my SASS:
$colors: (
primary: #f6861f,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222
);
If I use
.menu-inner .scroll-content{
background: $colors['primary'];
}
it doesn't work. How do I refer to primary inside my $colors array?
Your syntax isn't quite right - you can't use C-style associative arrays with SASS; you need to use the map-get function instead.
In your example, to access the primary colour you would do this:
.menu-inner .scroll-content {
background: map-get($colors, primary);
}
There's some more info on SASS maps in these articles.
Related
I have a simple sass map with colors. I loop through it and generate css vars. Works great so far.
$colors: (
primary: red,
secondary: blue,
)
#each $color, $value in $colors {
--#{$color}: #{$value};
}
Then I extended this map with themes. There I loop through again per theme and create the css vars. This also works great.
$colors2: (
theme-1: (
primary: red,
secondary: blue,
),
theme-2: (
primary: yellow,
secondary: pink,
)
)
#each $theme, $colors in $colors2 {
&[data-theme="#{$theme}"] {
#each $color, $value in $colors {
--#{$color}: #{$value};
}
}
}
But now I need to find a way to combine the two. Unfortunately I haven't found a way so far to loop through the following list, create the individual css vars and the data-attributes + css vars.
$colors3: (
primary: green,
secondary: purple,
theme-1: (
primary: red,
secondary: blue,
),
theme-2: (
primary: yellow,
secondary: pink,
)
)
Does anyone of you maybe have an idea how I can do this? In the end something like this should come out:
:root {
--color-primary: green;
--color-secondary: purple;
&[data-theme="theme-1"] {
--color-primary: red;
--color-secondary: blue;
}
&[data-theme="theme-2"] {
--color-primary: yellow;
--color-secondary: pink;
}
}
Thank you very much for your help!
Kind regards
Marco
i found a way to get it to work :)
here is my solution just in case, someone else needs it.
:root {
#each $key, $value in $colors {
#if type-of($value) == map {
&[data-theme="#{$key}"] {
#each $theme-key, $theme-value in $value {
--color-#{$theme-key}: #{$theme-value};
}
}
} #else {
--color-#{$key}: #{$value};
}
}
}
I am trying to customize scss in my project so that I can use css variables according to css selector applied on outermost element.
The basic Idea I have is to define color variables and then use those color variables to define semantic color variables in two different css selectors.
$primary: orange;
$primary-dark: redorange;
$warn: red;
$accent: grey;
$dark-grey: #757678;
$light-grey: #f7f7f7;
$error-text: $warn;
.light {
$background: $light-grey;
$button-bg: $primary;
}
.dark {
$background: $dark-grey;
$button-bg: $primary-dark;
}
This is one solution I tried, but in scss we cannot change scope of variables according to selectors.
So I tried using functions.
$white: #fff;
$light-grey: #eaeaea
$primry-dark: redorange;
$primary: orange;
$black: #000;
$semantic-colors: (
background: (
screen: $white,
tile: $light-grey,
),
buttons: (
primary: $primary
link: $white
icons: $primary-dark;
)
);
#function semantic-color($semantic-color:'background', $tone: "base") {
// #return red;
#return map-get(map-get($semantic-colors, $semantic-color), $tone);
}
.side-nav-link {
background-color: semantic-color(background, tile);
}
The above code works fine. but I want to have a color map based on a theme. for eg:
dark has its own semantic color map and light has its own and I can access based on scope.
.light {
$semantic-colors: (
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary,
link: $white,
icons: $primary-dark;
)
);
}
.dark {
$semantic-colors: (
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary;
)
);
}
I can create two different maps within semantic-color map:
$semantic-colors: (
light:(
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary
link: $white
icons: $primary-dark;
)
),
dark:(
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary;
)
)
);
and then modify my function to get color within a specific map based on $theme variable.
For eg:
$theme: dark;
#function semantic-color($semantic-color:'background', $tone: "base") {
// #return red;
#return map-get(map-get(map-get($semantic-colors, $theme), $semantic-color), $tone);
}
but I don't know a way to define $theme according to .light and .dark selectors.
If I try doing something like this:
.light {
$theme: light;
}
.dark {
$theme: dark;
}
and then use the $theme variable in the semantic-color function then I get the error $theme is not defined.
so my question is
"Is there a way I can define $theme or semantic-color function or $sematic-color map according to a CSS selector (.light or .dark in my case)?"
I have read sass documentation but could not find any solution to suit my situation.
Articles I referred to:
Theming in SASS
Creating a Color Language in Web Interfaces (with Sass Maps)
educba SASS Map
I am not quits sure if I did it completly right ... but as I see your idea and code in general works well.
The only thing seems to be: there had been some errors in your code seeting up $semantic-colors !?
This (correctedt version = only corrections in $semantic-colors) works here:
//########### SASS: demo file
//### VARS
$primary: orange;
$primary-dark: redorange;
$warn: red;
$accent: grey;
$dark-grey: #757678;
$light-grey: #f7f7f7;
$white: #ffffff;
$black: #000000;
$error-text: $warn;
$semantic-colors: (
light: (
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary,
link: $white,
icons: $primary-dark,
),
),
dark: (
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary,
),
),
);
//### METHODS
$theme: dark;
#function semantic-color($semantic-color: "background", $tone: "base") {
// #return red;
#return map-get(
map-get(map-get($semantic-colors, $theme), $semantic-color),
$tone
);
}
//### STYLES
.light {
$theme: light;
background: semantic-color('background', 'base');
}
//###########################
//###### CSS: compiled file
.light {
background: #ffffff; // if $theme changes to dark this becomes #000000
}
Because of your comment I believe to understand your question better now. So, according to your last comment I add an additional answer as it is more an explanation about the general howto than a concrete answer to your code.
First: I believe your code (SASS-map/-function) works the right way
To me it seems more a question about understanding how the theme technique works.
So let's start from the base:
1. What you need to do for theming in html:
// set a theme anchor with classes
// --> class to body
<body class="theme_light">
... code ...
... all elements within body will be styled by theme-light-classes
// or ALTERNATIVE do it with a marker where your app starts in html
// --> class to app-root-element
<div class="app_root theme_light">
... code ...
... all elements within app-div will by styled by theme-light-classes
</div>
</body>
2. Based on HTML what you nee in CSS:
Write the styling for your elements for both(!) themes based on the used marker technique (body or app) ...
// write styling classes for both themes (dark + light)
// as child selector based on the html theme-anchor-classes
/* stylings light theme */
.theme_light .content {
background: #theme-light-background-color;
color: #theme-light-font-color;
}
.theme_light .button {
background: #theme-light-button-background-color;
color: #theme-light-button-font-color;
}
/* stylings dark theme */
.theme_dark .content {
background: #theme-dark-background-color;
color: #theme-dark-font-color;
}
.theme_dark .button {
background: #theme-dark-button-background-color;
color: #theme-dark-button-font-color;
}
// if you anchor with app class your css-selectors would have to be
/* light theme */
.app_root.theme_light .content { ... }
.app_root.theme_light .content { ... }
/* dark theme */
.app_root.theme_dark .content { ... }
.app_root.theme_dark .content { ... }
3. Use your SASS-function/-map to achieve this in SASS
In this step we use your (still working) function and map from your question. Writing the CSS in SASS is as easy with nesting the element classes ...
// write themes dark & white nested to the anchor classes
// use function & map from question
.theme_light {
// set sass theme varible
// to get from function values for theme light
$theme: light;
// write stylings
// function will automatic return values for light theme
body {
background: semantic-color('background', 'base');
color: semantic-color('text-color', 'base');
}
button {
background: semantic-color('buttons', 'primary');
color: semantic-color('buttons-text', 'primary');
}
}
.theme_dark {
// set sass theme varible
// to get from function values for theme dark
$theme: dark;
// write stylings
// function will automatic NOW return values for light theme
body {
background: semantic-color('background', 'base');
color: semantic-color('text-color', 'base');
}
button {
background: semantic-color('buttons', 'primary');
color: semantic-color('buttons-text', 'primary');
}
}
//###
//### --> that will compile the needed css!!!
//###
//### NOTE:
//--> if you use app-anchor-class
//--> your nesting would be as follow
.app_root.theme_light { ... same code as above ... }
.app_root.theme_dark { ... same code as above ... }
HINTS:
As you see your function is a powerful tool: as shown in the example it leads to write identical code twice. If you write a SASS mixin (use directive #content to pass individual theme styles to it) you can reduce it so you are able to write all themes at once.
As you see the SASS variable $theme is used IN SASS as switch which changes your function semantic-color() to get the right color (light or dark).
There are many approches to realize theme stylings in SASS. This is one of the traditional methods and having a good organized map a very intuitive one.
SCSS
$colors: (
primary: red,
secondary: blue,
accent: #ddd,
) !default;
$colors: (
primary: green,
secondary: purple,
black: #000,
white: #fff,
);
#each $color, $value in $colors {
.alert-#{$color} {
color: $value;
}
}
Result
.alert-primary {
color: green;
}
.alert-secondary {
color: purple;
}
.alert-black {
color: #000;
}
.alert-white {
color: #fff;
}
I wanted to create a SASS framework something like bootstrap. Wanted to override theme colors. How can i merge these maps to get something like this? I want a simple solution.
Expected result
.alert-accent {
color: #ddd;
}
.alert-primary {
color: green;
}
.alert-secondary {
color: purple;
}
.alert-black {
color: #000;
}
.alert-white {
color: #fff;
}
You can use map-merge:
$colors: map-merge($colors, (
primary: green,
secondary: purple,
black: #000,
white: #fff
));
From the documentation, this function:
Returns a new map with all the keys and values from both $map1 and $map2.
This can also be used to add a new value or overrwrite a value in $map1, by passing a single key/value pair as $map2.
If both $map1 and $map2 have the same key, $map2’s value takes precedence.
I want to use a SCSS loop as below:
#each $var in dark, purple, green, cyan, silver, white {
.text-#{$var} {
color: nth($color-, $var);
}
.btn-#{$var} {
background-color: nth($color-, $var);
}
}
in order to use the following variables:
$color-dark: #0D0E1E;
$color-purple: #333366;
$color-green: #33cc99;
$color-cyan: #00cccc;
$color-silver: #ccc;
$color-white: #fff;
but it is not working.
$color-#{$var} was not working as well. Can I do this?
nth gets an item in a list. The first argument is the list, the 2nd is an index in the list. Also SASS thinks anything with a $ is a variable, so $color- is a variable. You haven't defined $color- as a variable, and that's not your intended use.
DOCS.
But you can get your desired result with a map...
DEMO
$color-dark: #0D0E1E;
$color-purple: #333366;
$color-green: #33cc99;
$color-cyan: #00cccc;
$color-silver: #ccc;
$color-white: #fff;
$colors: (
dark: $color-dark,
purple: $color-purple,
green: $color-green,
cyan: $color-cyan,
silver: $color-silver,
white: $color-white
);
#each $name, $val in $colors {
.text-#{$name} {
color: $val;
}
.btn-#{$name} {
background-color: $val;
}
}
I am looking to utilize a SASS Rules (#mixin, #extend, etc.) and/or control directives (#if, #for, #each, etc.) to generate classes for the color variables that I have defined.
Below is an example of what I am using currently, but I know that I can further simplify this to make it significantly less redundant.
// Colors
$navy: #37455a;
$blue: #abbdd3;
$cyan: #a3d9cb;
$peach: #ff9d7a;
// Backgrounds
.bg-navy{
background: $navy;
}
.bg-blue{
background: $blue;
}
.bg-cyan{
background: $cyan;
}
.bg-peach{
background: $peach;
}
// Text
.text-navy{
color: $navy;
}
.text-blue{
color: $blue;
}
.text-cyan{
color: $cyan;
}
.text-peach{
color: $peach;
}
I have tried a few different methods, but I always run into conflicts with mapping. I want to preserve the mapped variable in the object to use outside of these functions. This is what I have come up with so far:
// Colors for use in other partials
$navy: #37455a;
$blue: #abbdd3;
$cyan: #a3d9cb;
$peach: #ff9d7a;
// Mapped colors used for generating classes (Duplicated unfortunately)
$colors: (
$navy: #37455a;
$blue: #abbdd3;
$cyan: #a3d9cb;
$peach: #ff9d7a;
)
// Background class definition
#mixin bg{
.bg-#{$color}{
background: $color;
}
}
// Text class definition
#mixin text{
.text-#{$color}{
color: $color;
}
}
// Background class generation
#each $color in $colors{
#include bg($color);
}
// Text class generation
#each $color in $colors{
#include text($color);
}
While what I have above does not work, it's closer to what I am trying do accomplish. Has anybody solved for what I am attempting to do here? Any insight would be much appreciated as well!
One mixin to do it all!
$navy: #37455a;
$blue: #abbdd3;
$cyan: #a3d9cb;
$peach: #ff9d7a;
$colors: (
navy: $navy,
blue: $blue,
cyan: $cyan,
peach: $peach
);
#mixin gen-props($prefix, $property) {
#each $color-name, $color in $colors {
.#{$prefix}-#{$color-name} {
#{$property}: $color
}
}
}
#include gen-props('text', 'color');
#include gen-props('bg', 'background');