SASS/SCSS: Define variables based on other variables - sass

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

Related

How to use functions in :root in SCSS for custom properties?

I'm trying to generate custom properties in the :root using SCSS. I have a function called fluidClamp() that generates a clamp function for text sizes. It accepts a minimum value and a maximum value.
However, I can't get any functions to work in SCSS when they're used inside :root{}.
For example:
:root {
--text-s: fluidClamp(1.4, 1.6);
--text-m: fluidClamp(1.6,1.8);
}
It completely ignores the function, even though the function works everywhere else. What are my options?
You can't use function in your :root pseudo element.
To achive your goal, you need to declare in your :root the basic rules, like:
$text_s: 1.4;
$text_m: 1.6;
:root{
--text-s: $text_s;
--text-m: $text_m;
}
Then in your component you can call:
.myClass{
font-size: fluidClamp(var(--text-s), var(--text-m))
}
Hope it help.

How to make an alias for a Sass mixin with multiple arguments?

Since I couldn't find a Question for this specific problem, I will post the solution I came up with.
I want to create an alias for a Sass mixin which has multiple arguments (partially optional ones).
#mixin box(
$width,
$height,
$background-color: transparent
) {
width: $width;
height: $height;
background-color: $background-color;
}
For this mixin I want to create an alias which just takes all arguments given and passes them through to the original mixin:
#mixin box_alias(
$width,
$height,
$background-color: transparent
) {
#include box( $width, $height, $background-color );
}
It feels very redundant to keep listing all arguments again, this totally works agains the DRY principle. So I am looking for a more elegant solution.
In Sass you have the possibility to allow a mixin (or function) to have an arbitrary number of arguments. To do this you make the last argument an argument list by appending three dots (...) to its definition. If there is only one argument and it ends with the three dots, then the resulting arument list will contain all arguments passed to the mixin. This works very similar to the spread operator in ES2015.
The resulting argument can be passed on to original mixin, adding the three dots again to unfold them as separate arguments for the call:
#mixin box_alias($arguments...) {
#include box($arguments...);
}
This works well for positional and keyword arguments (even in combination) and also for optional arguments.

SASS HEX to RGB without 'rgb' prefix

The Question:
Is there a SASS function/technique that transforms a HEX value to a simple RGB string.
Simple here meaning just a string without it being enclosed in rgb() ?
E.g: #D50000 --> "213,0,0"
Why I need this:
I'm using Material Design Lite as my UI 'framework'. More specifically I'm using the SASS version so I can tweak the color variables according to my app's style-guide.
For some reason the color variables in _variables.scss of MDL take this format for color definitions:
$color-primary: "0,0,0" !default; // supposed to be black
which is really, really odd. I expected, at most, something along the lines of
$color-primary: rgba(0,0,0,1) !default;
My color variables are stored in another file called _globals.scss in which I store my variables in regular HEX format so I can easily reuse them in other places:
$brand-primary: #FA3166;
$brand-primary-dark: #E02C59;
I don't want to define 2 times my colours (1 HEX & 1 MDL-compatible RGB string), hence the reason I need to transform HEX to RGB-string.
#nicholas-kyriakides's answer works perfectly fine, but here is a more concise function using Sass interpolation.
#function hexToRGBString($hexColor) {
#return "#{red($hexColor)},#{green($hexColor)},#{blue($hexColor)}";
}
You can pass in either a hex either explicity or from rgb() or rgba() with opacity as 1.
For example:
$color-white: hexToRGBString(#fff) => "255,255,255"
$color-white: hexToRGBString(rgb(255,255,255)) => "255,255,255"
$color-white: hexToRGBString(rgba(#fff,1)) => "255,255,255"
I've hacked around it with a SASS function:
#function hexToString($hexColor) {
// 0.999999 val in alpha actually compiles to 1.0
$rgbaVal: inspect(rgba($hexColor,0.9999999));
// slice substring between 'rgba(' and '1.0)'
#return str-slice($rgbaVal, 6, str-length($rgbaVal)-6);
}
Usage:
$brand-primary: #333;
$color-primary: hexToString($brand-primary);
I think the MDL team intended to have a different way to customise the palette and I'm missing it, so if someone knows a better way to customise MDL's palette I'm open to suggestions. Either way this solves the original question.

Sass with compas, selecting all divs with x class before hyphen

I am using Sass and currently selecting my divs via:
[class*='inner-']{
padding: $pad;
}
But i have two variants of this div which are: -left, -right but i wanted to see if there was a better way rather than doing individual style blocks for each one, if i could merge it into one block.
My variants have a slight variation on the padding.
So something like:
[class*='inner-']{
padding: $pad;
-left{
atttribute
}
-right{
attribute
}
}
I might be over thinking this and making it pointlessly complex, but it's helping me learn lots so if anyone can shed some light on the best solution I'd appreciate it.
Not sure I've understood what you need properly, but I think you making it too complex.
Nice and simple solution:
%inner {
padding: somepadding;
}
.inner-left {
#extend %inner;
some other: attributes for left;
}
.inner-right {
#extend %inner;
some other: attributes for right;
}
We use placeholder (%inner), it's like a silent class, won't be outputed until called. Then extend it to those two classes. Nice, clean and maintainable solution.

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