SASS Color Weight Mixin - sass

I'm trying to create a color weight mixin. The result would be something like Google Material's color weights ( https://material.io/guidelines/style/color.html#color-color-palette ).
I'm hoping for a function where I could pass the base color and it would lighten / darken for each weight creating variables and classes for each weight.
Take the following manually done weights:
$color-blue: #1483ff;
$color-blue-100: lighten($color-blue, 30%);
$color-blue-200: lighten($color-blue, 20%);
$color-blue-400: lighten($color-blue, 10%);
$color-blue-500: $color-blue;
$color-blue-600: darken($color-blue, 10%);
$color-blue-700: darken($color-blue, 20%);
$color-blue-800: darken($color-blue, 30%);
$color-blue-900: darken($color-blue, 40%);
I was experimenting with something like this:
$colors: $color-blue-100, $color-blue-200, $color-blue-300;
#for $c from 1 through length($colors)-1 {
.bg-blue-#{$i} {
background: $c;
}
}
but that doesn't work and I still have to manually define the variables.

I took the approach of iterating over a predefined "palette" where the weights and percentages are static as well for colors. All you would have to do going forward is to add/change the colors defined.
$colors : (
"blue" : #1483ff,
"green" : #4CAF50,
"yellow" : #FFEB3B,
);
$palette : (
100 : 40%,
200 : 30%,
300 : 20%,
400 : 10%,
500 : 0,
600 : 10%,
700 : 20%,
800 : 30%,
900 : 40%
);
#each $name, $hex in $colors {
#each $weight, $percentage in $palette {
#if $weight < 500 {
.bg-#{"" + $name}-#{$weight} {
background-color: lighten($hex, $percentage);
}
} #else if $weight > 500 {
.bg-#{"" + $name}-#{$weight} {
background-color: darken($hex, $percentage);
}
} #else {
.bg-#{"" + $name}-#{$weight} {
background-color: $hex;
}
}
}
}
Which compiles to
.bg-blue-100 {
background-color: #e0efff;
}
.bg-blue-200 {
background-color: #add4ff;
}
.bg-blue-300 {
background-color: #7ab9ff;
}
.bg-blue-400 {
background-color: #479eff;
}
.bg-blue-500 {
background-color: #1483ff;
}
.bg-blue-600 {
background-color: #006ae0;
}
.bg-blue-700 {
background-color: #0052ad;
}
.bg-blue-800 {
background-color: #003a7a;
}
.bg-blue-900 {
background-color: #002247;
}
.bg-green-100 {
background-color: #d9eeda;
}
.bg-green-200 {
background-color: #b5dfb7;
}
.bg-green-300 {
background-color: #92cf94;
}
.bg-green-400 {
background-color: #6ec071;
}
.bg-green-500 {
background-color: #4CAF50;
}
.bg-green-600 {
background-color: #3d8b40;
}
.bg-green-700 {
background-color: #2d682f;
}
.bg-green-800 {
background-color: #1e441f;
}
.bg-green-900 {
background-color: #0e210f;
}
.bg-yellow-100 {
background-color: white;
}
.bg-yellow-200 {
background-color: #fffbd4;
}
.bg-yellow-300 {
background-color: #fff5a1;
}
.bg-yellow-400 {
background-color: #fff06e;
}
.bg-yellow-500 {
background-color: #FFEB3B;
}
.bg-yellow-600 {
background-color: #ffe608;
}
.bg-yellow-700 {
background-color: #d4be00;
}
.bg-yellow-800 {
background-color: #a19100;
}
.bg-yellow-900 {
background-color: #6e6300;
}

This should do it and no variables to define. You can see the output on sassmeister.
#mixin color-weight ($class, $base-color, $weight: 4) {
$bg-color: null;
#for $i from 1 through 8 {
#if $i < 4 {
$weight: $weight - 1;
$bg-color: lighten($base-color, $weight * 10%);
} #else if $i == 4 {
$weight: 0;
$bg-color: $base-color;
} #else {
$weight: $weight + 1;
$bg-color: darken($base-color, $weight * 10%);
}
.#{$class}-#{$i} { background-color: $bg-color; }
}
}
#include color-weight(bg-blue, #1483ff);
#include color-weight(mad, red);

Related

Sass variable not working in for

I have a problem converting a string to a variable, because it generates an error
I have tried in several ways to convert this variable into a line, in order to obtain the colors in the classes
c-gray + $i
SASS
$c-gray1: #666;
$c-gray2: #979797;
$c-gray3: #4c4c4c;
$c-gray4: #b9c6d1;
$c-gray5: #f7f8f9;
#for $i from 1 through 5 {
$colorsGrays: c-gray + $i;
$count: 1;
#each $color in $colorsGrays {
.gBgcGray#{$i} {
background-color: $color;
}
.gCGray#{$i} {
color: $color;
}
.g-bc--gray#{$i} {
border-color: $color;
}
$count: $count + 1;
}
}
OUTPUT:
.gBgcGray1 {
background-color: c-gray1;
}
.gCGray1 {
color: c-gray1;
}
.g-bc--gray1 {
border-color: c-gray1;
}
.gBgcGray2 {
background-color: c-gray2;
}
.gCGray2 {
color: c-gray2;
}
.g-bc--gray2 {
border-color: c-gray2;
}
.gBgcGray3 {
background-color: c-gray3;
}
.gCGray3 {
color: c-gray3;
}
.g-bc--gray3 {
border-color: c-gray3;
}
.gBgcGray4 {
background-color: c-gray4;
}
.gCGray4 {
color: c-gray4;
}
.g-bc--gray4 {
border-color: c-gray4;
}
.gBgcGray5 {
background-color: c-gray5;
}
.gCGray5 {
color: c-gray5;
}
.g-bc--gray5 {
border-color: c-gray5;
}
TEST: https://sass.js.org/
There is some way to generate a code with the correct one to get the values in the SASS and the OUTPUT
Sass can't resolve variables in this way, but you can use either list or map and resolve colors:
Using list:
$c-gray: #666 #979797 #4c4c4c #b9c6d1 #f7f8f9;
#for $i from 1 through 5 {
$colorsGrays: nth($c-gray, $i);
}
Using map:
$colors: (
c-gray1: #666,
c-gray2: #979797,
c-gray3: #4c4c4c,
c-gray4: #b9c6d1,
c-gray5: #f7f8f9,
);
#for $i from 1 through 5 {
$colorsGrays: map-get($colors, c-gray + $i);
}
Moreover in these cases you can use #each $colorGrays in $colors instead of #for

SCSS: How to use variables to write style classes ?

I was wondering whether there is a certain way to use variables that affect the style in SCSS.
I'm looking for something like:
var x = 1
.class1 {
if (x==1) {
background-color: red;
} else {
background-color: blue;
}
}
.class2 {
if (x==1) {
background-color: blue;
} else {
background-color: red;
}
}
You can use #if and #else
$x:1;
.class1 {
#if $x == 1 {
background-color: red;
} #else {
background-color: blue;
}
}
.class2 {
#if $x == 1 {
background-color: blue;
} #else {
background-color: red;
}
}

recursive sass in depth

I want to adapt padding like this.
it is possible to solve using sass mixin or another way
.list {
.item {
.text-box {
padding-left: 10px;
}
}
.list {
.item {
.text-box {
padding-left: 20px;
}
}
.list {
.item {
.text-box {
padding-left: 30px;
}
}
.list {
.item {
.text-box {
padding-left: 40px;
}
}
}
}
}
}
What about a loop with #for directive?
$list: ".list";
#for $i from 0 through 3 {
#{$list} {
.item {
.text-box {
padding-left: (10px + $i*10px);
}
}
}
$list: append($list, ".list");
}

SASS dynamic responsive classes mixin?

I'm trying to make a mixin to produce results similar to the following:
#media (max-width: 767px)
{
.m-text-left
{
text-align: left;
}
.m-text-right
{
text-align: right;
}
.m-text-center
{
text-align: center;
}
.m-float-right
{
float: right;
}
.m-float-left
{
float: left;
}
.m-float-none
{
float: none;
}
.m-text-justify
{
text-align: justify;
}
.m-hide
{
visibility: hidden;
overflow: hidden;
max-height: 0;
}
.m-remove
{
display: none;
}
}
/* Portrait tablet to landscape */
#media (min-width: 768px) and (max-width: 1029px)
{
.t-text-left
{
text-align: left;
}
.t-text-right
{
text-align: right;
}
.t-text-center
{
text-align: center;
}
.t-float-right
{
float: right;
}
.t-float-left
{
float: left;
}
.t-float-none
{
float: none;
}
.t-text-justify
{
text-align: justify;
}
.t-hide
{
visibility: hidden;
overflow: hidden;
max-height: 0;
}
.t-remove
{
display: none;
}
}
/* Landscape to small desktop */
#media (min-width: 1030px)
{
.d-text-left
{
text-align: left;
}
.d-text-right
{
text-align: right;
}
.d-text-center
{
text-align: center;
}
.d-float-right
{
float: right;
}
.d-float-left
{
float: left;
}
.d-float-none
{
float: none;
}
.d-text-justify
{
text-align: justify;
}
.d-hide
{
visibility: hidden;
overflow: hidden;
max-height: 0;
}
.d-remove
{
display: none;
}
}
This is the mixin I wrote:
#mixin respond($responsive-classes) {
#each $screen, $query in (
m: max-width $small-screen, // Phones
p: min-width $small-screen+1 max-width $medium-screen, // Phones to Phablets
t: min-width $medium-screen+1 max-width $large-screen, // Phablets to Tablets
l: min-width $large-screen+1 max-width $wide-screen, // Tablets to Desktops
d: min-width $wide-screen+1) { // Desktops
#include media($query, $grid-columns) {
#each $selector, $properties in $responsive-classes {
#if (length($properties) == 1 AND length(nth($properties, 2)) > 1) {
#each $value in nth($properties, 2) {
.#{$screen}-#{$selector}-#{$value} {
#{nth($properties, 1)}: #{$value};
}
}
} #else {
#each $property, $value in $properties {
.#{$screen}-#{$selector} {
#{$property}: #{$value};
}
}
}
}
}
}
}
This is how I used it:
#include respond((
(text, (text-align, (left, right, center, justify))),
(float, (float, (left, right, none))),
(hide, (visibility, hidden), (overflow, hidden), (max-height, 0)),
(remove, (display, none))
));
This is the result I'm getting:
#media screen and (max-width: 480px) {
.m-float,
.m-text {
left: right
}
}
#media screen and (min-width: 481px) and (max-width: 620px) {
.p-float,
.p-text {
left: right
}
}
#media screen and (min-width: 621px) and (max-width: 955px) {
.t-float,
.t-text {
left: right
}
}
#media screen and (min-width: 956px) and (max-width: 1200px) {
.l-float,
.l-text {
left: right
}
}
#media screen and (min-width: 1201px) {
.d-float,
.d-text {
left: right
}
}
.hide {
visibility: hidden;
overflow: hidden;
max-height: 0
}
Ignore the media queries; I know they're different. It's the overall final result that I want.
I was putting in lists instead of maps.
The Mixin:
#mixin respond($modifier-class) {
#each $screen, $query in (
m: max-width $small-screen, // Phones
p: min-width $small-screen + 1 max-width $medium-screen -1, // Phones to Phablets
t: min-width $medium-screen max-width $large-screen, // Phablets to Tablets
l: min-width $large-screen + 1 max-width $wide-screen - 1, // Tablets to Desktops
d: min-width $wide-screen) { // Desktops
#include media($query) { // Mixin from Bourbon's Neat
#each $selector, $rules in $modifier-class {
#each $property, $values in $rules {
#if (type-of($values) == "list") {
#each $value in $values {
.#{$screen}-#{$selector}-#{$value} {
#{$property}: $value;
}
}
} #else {
.#{$screen}-#{$selector} {
#{$property}: $values;
}
}
}
}
}
}
}
The call:
$modifier-classes: (
text: ( text-align: (left, right, center, justify) ),
float: ( float: (left, right, none) ),
hide: ( visibility: hidden,
overflow: hidden,
max-height: 0, ),
remove: ( display: none )
);
#include respond($modifier-classes);

sass parent of parent specificity

I write CSS in BEM style and have this code:
.nav {
&__list {
&__item {
}
}
&__link {
&--active {
}
}
}
How do I get .nav .nav__link--active and .nav__link.nav__link--active from code above? How can I enhance the specificity by this method?
There is no magic method for this. Store the desired selector as a variable and nest like normal.
.nav {
$sel: &;
&__list {
&__item {
color: red;
#{$sel} & {
border: 1px solid;
}
}
}
&__link {
&--active {
color: blue;
#{$sel} & {
border: 1px dashed;
}
}
}
}

Resources