Naming Color Variables in SASS - 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);
}

Related

SASS - Complement function on a variable from another scope

I have two separate SASS files among many, on a ReactJS repository, such as _main.sass and _partials.sass. They are combined using #use on a separate file named index.css.
The SASS package as a dependency is just sass via npm.
_main.sass and all of its variables can be accessed by _partials.sass, thanks to #use "./main" as *.
I have the following code on _main.sass which detects OS preference for dark mode:
#media (prefers-color-scheme: light)
body
background-color: $white
color: $black
#media (prefers-color-scheme: dark)
body
background-color: $dark
color: $light
All of these color variables are defined and they're working well.
But the problem is that I need to use complement() function on the background-color which is currently active, in _partials.sass.
The main issue seems to me that when I assign a variable e.g. $accent on both ends of the media queries, the variable does not get picked up by the remote file. I could not wrap my head around to do it in such way, since I'm only a beginner at coding SASS.
Unfortunately, I need the plain CSS #media query implementations for automatically detecting the preference. But any suggestion is appreciated in case it is impossible to keep it like that and achieve what I wanted.
Thank you!
I've found the solution myself.
So, I was trying to make a light/dark theme compliant SASS implementation.
What complement function does is that it rotates the color in the input for 180deg on the RGB hue. I needed this to get corresponding inverted-like colors for each color, for better dark-mode contrast. The difference between invert and complement are listed here.
But, I realized that I did not need that. Here is the code for my theme implementation using SASS.
// rainbow
$blue: #00a4ef
$yellow: #f4b400
$red: #db4437
$green: #61b500
$purple: #6e14ef
$pink: #ff0090
$carmine: #c6004b
// monochroma
$white: #fff
$light: #f5f5f5
$lgray: #c2c2c2
$dgray: #6e6e6e
$ldark: #363636
$dark: #232323
$black: #000
$themes: (light: (logo: url("../static/logo-light.svg"), bg: $white, card-bg: $light, text: $black, link: $red, hover: $pink, active: $carmine, border: $lgray, button: $yellow), dark: (logo: url("../static/logo-dark.svg"), bg: $dark, card-bg: $ldark, text: $light, link: $red, hover: $pink, active: $carmine, border: $dgray, button: $purple))
#mixin themeProperty($theme, $property, $color, $additionalProperties)
#if $additionalProperties
#{$property}: unquote(map-get($theme, $color) + " " + $additionalProperties)
#else
#{$property}: unquote(map-get($theme, $color))
#mixin theme($property, $color, $additionalProperties: "")
$light: map-get($themes, light)
$dark: map-get($themes, dark)
#media (prefers-color-scheme: light)
#include themeProperty($light, $property, $color, $additionalProperties)
#media (prefers-color-scheme: dark)
#include themeProperty($dark, $property, $color, $additionalProperties)
There is a color map named "themes" which lists each color for light and dark themes for different use cases.
Furthermore, the mixins match the exact color for exact usage for the desired theme mode, whichever is being used by the client-side (browser or OS), thanks to #media queries.
For example, if you'd like to color a background-color using the button preset on the theme mapping, the usage is as follows:
#include theme("background-color", button)

Sass: rgba function is not working as per documentation

I have two examples that I'm trying to solve:
Example 1
$test: #101E41
body
--colors-dim: rgba(#{$test}, 0.64)
Output: rgba(#101E41, 0.64)
Example 2
body
--colors-active: #101E41
--colors-dim: rgba(var(--colors-active), 0.64)
Output: rgba(var(--colors-active), 0.64)
Both of these look like are examples that should be valid as shown here: https://sass-lang.com/documentation/modules#rgb
Is there something I'm missing?
You need to make use of interpolation to use Sass inside CSS Custom Properties
CSS custom properties, also known as CSS variables, have an unusual declaration syntax: they allow almost any text at all in their declaration values. What’s more, those values are accessible to JavaScript, so any value might potentially be relevant to the user. This includes values that would normally be parsed as SassScript.
Because of this, Sass parses custom property declarations differently than other property declarations. All tokens, including those that look like SassScript, are passed through to CSS as-is. The only exception is interpolation, which is the only way to inject dynamic values into a custom property.
$bar: #900;
:root {
--foo: #{rgba($bar, 0.5)};
}
Results in:
:root {
--foo: rgba(153, 0, 0, 0.5);
}
For your second example, you're going to have to get a little... creative... since Sass will bail and ignore any CSS Custom Property syntax it sees, you can't make use of Sass's rgba function with Custom Properties - the Sass compiler won't resolve the values for you.
Thankfully, you can still use the native CSS rgba function with Custom Properties, the only downside is that you'll need to break your hexadecimal value into its R, G, and B values.
#function toRGB($color)
#return red($color), green($color), blue($color)
$bar: #900
:root
--foo: #{$bar}
--foo-rgb: #{toRGB($bar)}
--foo-dim: #{rgba($bar, 0.5)}
--foo-dim: rgba(var(--foo-rgb), 0.5)
.button
background-color: var(--foo-dim)
Compiles to:
:root {
--foo: #900;
--foo-rgb: 153, 0, 0;
--foo-dim: rgba(153, 0, 0, 0.5);
--foo-dim: rgba(var(--foo-rgb), 0.5);
}
.button {
background-color: var(--foo-dim);
}
https://www.sassmeister.com/gist/39ffc57c492de73066831afe5a9696f6

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.)

SASS for each interpolation error when export css in compressed mode

I have a map declared like below
Map Definition
$color-array:(
black:#4e4e4e,
blue:#0099cc,
dark-blue:#14394e,
green:#2ebc78,
white:#ffffff,
orange:#ed6a0e
);
and calling the same in for each loop to generate class for text color and background color like below
#each $color-name, $color-value in $color-array{
.#{$color-name}{
color: $color-value !important;
}
.bg-#{$color-name}{
background: $color-value !important;
}
}
I am using gruntjs for for compilation, when i set output style to compressed it gives below error
You probably don't mean to use the color value #000' in interpolation
here. It may end up represented as #000000, which will likely produce
invalid CSS. Always quote color names when using them as strings (for
example, "#000"). If you really want to use the color value here, use
"" + $color-name'.
Error: Invalid CSS after ".": expected class name, was "#000"
on line 25 of SCSS/_base.scss
from line 5 of scss/style.scss
But when i set output style to expanded it runs fine.
In your colors array, change all the key double-quoted string keys and things should work.
$color-array:(
"black":#4e4e4e,
"blue":#0099cc,
"dark-blue":#14394e,
"green":#2ebc78,
"white":#ffffff,
"orange":#ed6a0e
);
An alternative of changing the SCSS code would be to make sure the variable is a string like the error message mentioned
#each $color-name, $color-value in $color-array{
.#{"" + $color-name}{
color: $color-value !important;
}
.bg-#{"" + $color-name}{
background: $color-value !important;
}
}

Resources