how to reference a property inside of a map object - sass

I have a map of colors, and would like to define subsequent colors in the map based on colors defined earlier within the map.
$colors: (
primary: #184770,
secondary: #0969A2,
white: #fff,
black: #000,
green: #24b206,
blue: #428bca,
purple: #813c8e,
grey: (lighten( black, 25%)),
grey-light: (lighten( black, 35%)),
grey-dark: (lighten( black, 15%))
);
I would like to specify grey, grey-light and grey-dark based on map-get($colors, black).
The example above works only because it references inherent color "black" rather than map-get($colors, black)
Can you reference a property inside the same map object?

No, you cannot reference a map's property inside the same map object. The map is not truly defined until the semi-colon is reached, so before that point, its own properties are unavailable to refer to. Here's a similar existing question and answer.
If you want to add subsequent values based on initially defined values, one route is with a combination of the map-get and map-merge functions:
$base-colors: (
black: #000
);
$extended-colors: (
grey: lighten(map-get($base-colors, black), 25%),
grey-light: lighten(map-get($base-colors, black), 35%),
grey-dark: lighten(map-get($base-colors, black), 15%)
);
$colors: map-merge($base-colors, $extended-colors);
Note: map-merge performs a shallow merge that is best for flat one-dimensional maps; if you are dealing with merging deeper multidimensional maps, you may want to define and use a recursive function rather than map-merge.

Related

Create gradient map in sass

I'm trying to generate a LCH gradient map with 2 gradients in SASS, where red-0 is super white red, red-1000 is super red, and red-2000 is super black red:
$colors: (
red-0: #FCF5F5,
red-100: #FFE2E2,
red-200: #FFCFCD,
red-300: #FFBCB8,
red-400: #FFA9A3,
red-500: #FF958C,
red-600: #FF8175,
red-700: #FF6C5E,
red-800: #FF5545,
red-900: #FF3A2B,
red-1000: #FC0A0A,
red-1100: #E60013,
red-1200: #D00017,
red-1300: #BA0019,
red-1400: #A4001A,
red-1500: #8F0019,
red-1600: #790118,
red-1700: #640316,
red-1800: #500512,
red-1900: #3C060C,
red-2000: #2A0303
);
Is there a way to generate this with an algorithm?

Get Palette Contrast Hue Based on Current Theme

I have the following palettes, with various hue values, being applied to multiple themes in my material-theme.scss file:
$green: mat-palette($mat-green, A400);
$blue: mat-palette($mat-light-blue, A400);
$red: mat-palette($mat-red);
$red-warn: mat-palette($mat-red, A100);
In my material-styles.scss file, I have a mixin that is used to define styles based on the current theme:
#mixin style-theme($theme) {
$p: map-get($theme, primary);
$a: map-get($theme, accent);
$w: map-get($theme, warn);
$primary: mat-color($p);
$accent: mat-color($a);
$warn: mat-color($w);
$primary-contrast: mat-contrast($p, 500);
$accent-contrast: mat-contrast($a, 500);
$warn-contrast: mat-contrast($w, 500);
// Apply styling based on values above
}
Themes are created as follows:
.light-green {
$default-theme: mat-light-theme($green, $blue);
#include style-theme($default-theme);
#include angular-material-theme($default-theme);
}
Is it possible for me to get the contrast of the currently applied palette? As it is now, I am only able to hard-code the $hue value for the mat-contrast function.
StackBlitz Demo
There are six 'special' keys that are automatically added to a palette when you use mat-palette():
default
lighter
darker
default-contrast
lighter-contrast
darker-contrast
Each base palette contains all of the colors mapped to the keys 50, 100, ... 900, A100, A200, A400, A700. It also contains a sub-palette mapped to the key 'contrast' with a set of contrast colors mapped to the same keys. The colors assigned to the special keys correspond to the hue values passed in to mat-palette(), which default to 500, 100, and 700 respectively for default, lighter, and darker. The '*-contrast' mapped colors are pulled from the contrast sub-palette using the same hue value keys.
When you call mat-color() without a hue key it uses default as the key. But you could use any of the special keys so that you don't need to know which hue values are actually mapped to the special keys.
So for example, you could call mat-color($green, default-contrast) to get the proper contrast color for the default color in your green palette.
I was able to figure it out by inspecting the theming for MatToolbar.
You can get the contrast color value for a palette using the following:
$contrast: mat-color($palette, default-contrast);
See revised StackBlitz Demo

SASS/SCSS: Define variables based on other variables

How does one define variables with the use of other variables in SASS?
This is how one could do it with LESS:
// import Google Material Colors
// returns variables ie #blue-500, #blue-400 etc
#import 'material.colors.less';
// base
#_color: 'blue';
#_secondary: 'amber';
// primary colors
#color-primary: ~"#{#{_color}-500}";
#color-primary-bright: ~"#{#{_color}-300}";
#color-primary-brighter: ~"#{#{_color}-200}";
#color-primary-brightest: ~"#{#{_color}-50}";
// secondary colors
#color-secondary: ~"#{#{_secondary}-500}";
#color-secondary-bright: ~"#{#{_secondary}-300}";
#color-secondary-brighter: ~"#{#{_secondary}-200}";
#color-secondary-brightest: ~"#{#{_secondary}-50}";
The LESS-way certainly isn't clean and dandy, but -- it works™
The idea is to set a base primary and then just set the other color(s) dynamically based on that.
I can't imagine that one would have to loop/map etc just to do this with SASS?(!)
Sass does not support dynamic variables, period.
You will need to use maps, but I'm not sure this will help you in this specific case (as you are already using external colors):
#import 'material.colors';
$colors: (
primary: (
default: $blue-500,
bright: $blue-300,
brighter: $blue-200,
brightest: $blue-50
),
secondary: (
default: $amber-500,
bright: $amber-300,
brighter: $amber-200,
brightest: $amber-50
)
);
#function color($color, $brightness: default) {
#return map-get(map-get($colors, $color), $brightness);
}
h1 {
color: color(primary, bright);
background-color: color(secondary);
}
Of course you can do it. You can use neat sass color functions and do what you need in a nice and clean way. Take a look at lighten function and even darken function, or at other color functions in general.
Basically, you do it like this:
$primary-color: #08f;
$primary-light-color: lighten($primary-color, 20%);
$primary-lighter-color: lighten($primary-color, 30%);
$primary-dark-color: darken($primary-color, 20%);
$primary-darker-color: darken($primary-color, 30%);
You can see this in action here:
https://codepen.io/anon/pen/PjXRjM?editors=1100#0
Or if you feel like it's a good idea, you could automate it a little with lists and loops. Take a look at this article: https://www.sitepoint.com/managing-color-values-with-sass/, where its author gets through it. (To be honest, I'm not sure if that a good idea at all, as it easily may be hard to understand and maintain later. That's another topic, though.)

How do I change an image (icon's) color in css

I have some images representing icons that consists of blue signs and transparent background. I display them using css:
.icon {
background: rgba(0, 0, 0, 0) url("images/icons/my-icon.png") no-repeat scroll 5px center;
}
My icon looks like this one: https://cdn2.iconfinder.com/data/icons/large-svg-icons-part-3/512/zoom_search_find_magnifying_glass-256.png
I want to be able to change the color of the blue using css. I tried to use CSS3's filter function.
The idea is that I have the hex code and I transform it to RGB and later HSL (hue, saturation and luminance). In the end I'll have for each color a value between 0 and 360 (a degree). See for example this image: http://lodev.org/cgtutor/images/hslhuecircle.jpg .
I'm using this filter function:
filter: hue-rotate(220deg) saturate(100);
Where 220deg is the int value of the hue. So the hue (initially a float value) aproximated up is 220.
Take example red: #ff0000
The hue details are:
array(4) {
["hue"]=>
int(0)
["saturation"]=>
int(100)
["luminance"]=>
float(50)
["degrees"]=>
int(0)
}
So the css becomes:
.icon {
background: rgba(0, 0, 0, 0) url("images/icons/my-icon.png") no-repeat scroll 5px center;
filter: hue-rotate(0deg) saturate(100);
}
But in this case, the blue becomes #9AF8FF (which is not red).
In order to obtain red, I should use:
filter: hue-rotate(195deg) saturate(100);
The hue-rotate values can be between 0 and 360, just like degrees. In my case the results are inversed, instead of obtaining red for 0degrees, I obtain the value that can be find on the following image at 195 degrees: http://lodev.org/cgtutor/images/hslhuecircle.jpg .
Is there any css filter or other solution that can help me to change the image color using css? I played with other CSS3 filters but I couldn't change the color to the desired one.
I have an application where users can select the desired color, the only problem is with existing image icons.
Any help will be great, anticipate thanks!
When I wrote the question I found a possible solution. In my case, the results were reversed.
For red, #ff0000 I obtained 0 degrees. I realized that with css3's filter hue-rotate, the red is not at 0, but it starts at 180. So for each hue/degree value that I obtain, I add 180. In this way, I can obtain the desired color.
After this change, the hsl:
array(4) {
["hue"]=>
int(0)
["saturation"]=>
int(100)
["luminance"]=>
float(50)
["degrees"]=>
int(0)
}
become:
array(4) {
["hue"]=>
int(180)
["saturation"]=>
int(100)
["luminance"]=>
float(50)
["degrees"]=>
int(180)
}
I tried it for green and other colors and it works well. If you have a better idea to change the image color with CSS, one that doesn't use the filter function "hue-rotate", I'll be glad to hear about it.
EDIT
I found the solution.
1) I'm using the solution explained above (I add 180 to my degrees).
2) I'm using brightness filter also
So My filter looks like:
filter: hue-rotate(350deg) saturate(100) brightness(1);
This filter changes the icon's color to this color: #00FFFF .
So the solution work 100%. I'm sending color code and brightness and I dynamically calculate the filter values. For darker colors use a lower value for brightness (under 0.5) and for brighter colors use values above 0.5.

Naming Color Variables in SASS

When creating a color scheme in SASS what's the conventional variable names for defining colors?
I know using color names are bad. Such as:
$blue
$red
$green
But I've not seen an alternative. I'm struggling for variable names for colors on the site that convey meaning.
Any ideas?
I found another idea in "SASS & Color Variables" article. The solution suggested by Sacha Greif is to use some variables to store descriptive color names, and some other to assign those colors to their functions:
// first we set descriptive variables:
$darkgrey: #333333;
$blue: #001eff;
// then we set functional variables:
$text_color: $darkgrey;
$link_color: $lightblue;
$border_color: $lightblue;
.myClass {
color: $text_color;
border-color: $border_color;
}
a {
color: $link_color;
}
I'm just beginning with SASS and don't know which approach is more practical, but I like the way it separates colors from their function.
In my personal experience the most useful way to name colors is to do it in regards of the color's function, such as
$background
$contrast
$text
$aside
$link
And so on. Of course which colors and name may depend on the design.
Then you may have different and exchangeable color schemes defined on different styles, such as:
_dark_scheme.scss
_light_scheme.scss
_pastels.scss
The idea here, is that you can use the same color variables in your main stylesheets, and do not depend on specific colors.
I like the idea of combining generic to specific naming (good for code completion) and description/functional naming. So you have something like this:
// Descriptive naming
$color-gray-light: #f3f3f3;
$color-gray-dark: #999999;
$color-red: red;
// Functional naming
$link-color: $color-red;
$link-border-color: $color-gray-light;
You can even create a mixin for greys (in the example RGBA is used for transparency, for example black on a red background would be more visible if it is 80% transparent black rather than dark grey).
#mixin grey($intensity: 0.5, $type: color) {
#{$type}: rgba(black, $intensity);
}
.i-am-50-percent-gray {
#include grey(0.5, color);
}
Give the result
.i-am-50-percent-gray {
color: rgba(0, 0, 0, 0.5);
}

Resources