Referencing a sass/scss variable on the fly - css

I am trying to get a mixin done to achieve the following.
Im having a list of social buttons. They each share the same styles except the background-color and :hover states.
My current SASS approach. (will return invalid CSS error)
#mixin btn-social($network) {
.#{$network} {
background: $#{$network}; // trying to reference a global variable
&:hover, &:focus {
background: darken($#{$network}, $darken-modifier);
}
}
}
To render like this:
.facebook {
background: blue; // stored in $facebook
}
.facebook:hover, .facebook:focus {
background: darkblue; //darkend value above
}
I'm somehow lacking the right terms for a proper google search. I'd appreciate a push in the right direction.
Thanks for the help.

You can use a sass map to store the color variables and then find the right color using the name you pass into your mixin like so jsfiddle:
$colors: (
facebook: blue,
twitter: red
);
$darken-modifier: 100%;
#mixin btn-social($network) {
.#{$network} {
background: map-get($colors, $network);
&:hover, &:focus {
background: darken(map-get($colors, $network), $darken-modifier);
}
}
}
#include btn-social(facebook);
#include btn-social(twitter);
<a class="facebook">
facebook
</a>
<a class="twitter">
twitter
</a>
Edit: updated to include #TomOakley's suggestion below.

Please try the following:
#mixin btn-social($network, $color, $darkColor) {
#{$network} {
background: $color;
&:hover, &:focus {
background: $darkColor;
}
}
}
.foo {
#include btn-social('.facebook', blue, darkblue)
}
This compiles to:
.foo .facebook {
background: blue;
}
.foo .facebook:hover, .foo .facebook:focus {
background: darkblue;
}
Check out this reference for SASS interpolation.

Related

CSS :root variables and SASS Functions

in the Header of my HTML-Page i set the following CSS Variables:
:root{
--data-color-primary: #ffcc00;
--data-color-secondary: #4b4b4b;
}
In my SASS-File i use it as follow:
DIV.color {
&.color-primary {
background-color: var(--data-color-primary);
}
&.color-secondary {
background-color: var(--data-color-secondary);
}
}
Now i try to set the font-color depending on the brightness of the background-color:
#function set-notification-text-color($color) {
#if (lightness($color) > 60) {
#return #000000;
} #else {
#return #ffffff;
}
}
DIV.color{
&.color-primary {
background-color: var(--data-color-primary);
color: set-notification-text-color(var(--data-color-primary));
}
}
But in my SASS-compliler i get the following i get the following Error:
Error: argument $color of lightness($color) must be a color
How is ist possible to hand over der CSS variable to the function.
My Problem is, the CSS Variables are set in the Backend of my CMS by User (Liferay 7) an will be rendered in a *.FTL-File and is printed in the HTML-Code.
$primary: ${clr_primary};
$secondary: ${clr_primary};
and then i cant use the SASS-Variable $primary in my SASS-File.
Use SASS variables in your CSS variables.
$primary: #ffcc00;
$secondary: #4b4b4b;
:root{
--data-color-primary: #{$primary};
--data-color-secondary: #{$secondary};
}
Now call your mixin
DIV.color{
&.color-primary {
background-color: $primary;
color: set-notification-text-color($primary);
}
}
Another options would be to create a mixin which retrieves the CSS variable
#function color($color-name) {
#return var(--data-color-#{$color-name});
}
Now call that function like so
DIV.color {
&.color-primary {
background-color: color(primary);
color: set-notification-text-color(color(primary));
}
}
Check out this link for usefull information about combining CSS and SASS variables
https://codepen.io/jakealbaugh/post/css4-variables-and-sass
If you need to change CSS variables outside of :root you can do the following
.class {
// sass-lint:disable no-duplicate-properties
#{--background}: transparent;
#{--background-focused}: transparent;
// sass-lint:enable no-duplicate-properties
}
and this compiles to
.class {
--background: transparent;
--background-focused: transparent;
}

SASS – looping through map via mixin doesn’t compile CSS

what I have is a simple SASS color map:
$brand_col: (
def: blue,
mus: red,
ser: yellow
);
The following:
#each $brand, $col in $brand_col {
body.#{$brand} {
background: $col;
}
}
leads to expected output:
body.def { background: blue; }
body.mus { background: red; }
body.ser { background: yellow; }
When I try to put the same thing into a mixin like so:
$color: null;
#mixin branding {
#each $brand, $col in $brand_col {
&.#{$brand} {
$color: $col;
#content;
}
}
}
.body { #include branding { background: $color; } }
I would expect the same output, but nothing is getting compiled at all. I copied the mixin from a sass specific site and don’t fully understand the whole process. Any hints what I'm doing wrong?
Thanks
Ralf
To achive the same result as in your first example, have two options:
Option 1
Make a simple non-reusable mixin:
$brand_col: (
def: blue,
mus: red,
ser: yellow
);
#mixin branding {
#each $brand, $col in $brand_col {
&.#{$brand} {
background: $col;
}
}
}
.body {
#include branding;
}
This will compile to:
.body.def {
background: blue;
}
.body.mus {
background: red;
}
.body.ser {
background: yellow;
}
Option 2
Make a reusable mixin, so you can pass the color map to apply:
$brand_colors: (
def: blue,
mus: red,
ser: yellow
);
#mixin branding($colors) {
#each $class, $color in $colors {
&.#{$class} {
background: $color;
}
}
}
.body {
#include branding($brand_colors);
}
// Latter you can use it to apply the same 'branding' for any other element
div {
#include branding($brand_colors);
}
Will compile to:
.body.def {
background: blue;
}
.body.mus {
background: red;
}
.body.ser {
background: yellow;
}
div.def {
background: blue;
}
div.mus {
background: red;
}
div.ser {
background: yellow;
}
You could even implement a second parameter to the mixin to specify which css property you want to apply, with background as a default:
#mixin branding($colors, $property: background) {
#each $class, $color in $colors {
&.#{$class} {
#{$property}: $color;
}
}
}
// Latter you can use it to apply the same 'branding' for any other element and property
h1 {
#include branding($brand_colors, color);
}
Will compile to:
h1.def {
color: blue;
}
h1.mus {
color: red;
}
h1.ser {
color: yellow;
}
You can find out more about mixins here.
Hope it helps!
What do you mean by $color: $col;? no such property like "null" in CSS, because when you set $color: null at top and then trying to set a property $color: $col; you actually trying to set like that null: blue; this is nothing mean anything to compiler.
I think you no need #content directive use here. You should try just following way:
$brand_col: (
def: blue,
mus: red,
ser: yellow
);
#mixin branding {
#each $brand, $col in $brand_col {
&.#{$brand} {
background: $col;
}
}
}
.body { #include branding(); }

Sass - What's the difference between map-get and simple variable?

I'm new with Sass stuff and I've been reading about different ways to use variables, this principle I'm trying to apply is just for colors, some of the solutions I've found were something like this (map-get):
$colors: (
lighestGray: #F8F8FA,
lightGray: #A5ACBA,
light: #FFFFFF,
dark: #000000,
link: #428bca,
linkHover: #555,
navBlue: #7AC243,
navGreen: #009CDC,
);
Then you use it on your class like this:
.my-class {
color: map-get($colors, dark);
}
And the other way is to use:
$color-black: #000000;
Then you use it like this:
.my-class {
color: $color-black;
}
My question is, which option is better? or map-getfunction has another purpose?, has Sass a pattern for this or it depends on each web-developer?.
Thanks for helping me out!.
Regards.
The differences is that when you use $map variables, they are best designed for using through iterations or using #each.
Sample case:
SCSS
// Map variable
$icons: (
facebook : "\f0c4",
twitter : "\f0c5",
googleplus : "\f0c6",
youtube : "\f0c7"
);
// Mixin doing the magic
#mixin icons-list($map) {
#each $icon-name, $icon in $map {
#if not map-has-key($map, $icon-name) {
#warn "'#{$icon-name}' is not a valid icon name";
}
#else {
&--#{$icon-name}::before {
content: $icon;
}
}
}
}
// How to use it
.social-link {
background-color: grey;
#include icons-list($icons);
}
CSS
// CSS Output
.social-link {
background-color: grey;
}
.social-link--facebook::before {
content: "";
}
.social-link--twitter::before {
content: "";
}
.social-link--googleplus::before {
content: "";
}
.social-link--youtube::before {
content: "";
}
This code was taken from my own answer in the following post but the answer is a case use of #each :)
Hope this help you
Example making a theme with css variables with fallback color
see codepen css variables
// VARS (FOR FALLBACK)
// -------------------
$theme-base: #70c1ac;
$theme-base-aa: adjust-color($theme-base, $blue: 125);
// PROCESSED THEME
$theme-color: $theme-base;
$theme-color-dark: darken($theme-color, 20%);
$theme-color-light: lighten($theme-color, 20%);
$theme-color-mixed: mix(#fff, $theme-color, 75%);
$theme-color-trans: transparentize($theme-color, .4);
// PROCESSED SECONDARY
$theme-color-aa: $theme-base-aa;
$theme-color-aa-dark: darken($theme-color-aa, 20%);
$theme-color-aa-light: lighten($theme-color-aa, 20%);
$theme-color-aa-mixed: mix(#fff, $theme-color-aa, 75%);
$theme-color-aa-trans: transparentize($theme-color-aa, .4);
$theme-colors: (
"aa-dark": $theme-color-aa-dark,
"aa-light": $theme-color-aa-light,
"aa-mixed": $theme-color-aa-mixed,
"aa-trans": $theme-color-aa-trans,
aa: $theme-color-aa,
dark: $theme-color-dark,
light: $theme-color-light,
mixed: $theme-color-mixed,
theme: $theme-color,
trans: $theme-color-trans,
);
#mixin themeColor ($prop, $color: null) {
#if ($color) {
#{$prop}: map-get($theme-colors, $color);
#{$prop}: var(--theme-color-#{$color})
} #else {
#{$prop}: map-get($theme-colors, theme);
#{$prop}: var(--theme-color);
}
}
#mixin setThemeColors($base1: "", $base2: "") {
// BASE THEME COLORS
$color-base: $theme-base;
$color-aa: $theme-base-aa;
#if ($base1) {
$color-base: $base1;
$color-aa: $base2;
}
// PROCESSED THEME COLORS
$color-aa-dark: darken($color-aa, 20%);
$color-aa-light: lighten($color-aa, 20%);
$color-aa-mixed: mix(#fff, $color-aa, 75%);
$color-aa-trans: transparentize($color-aa, .5);
$color-aa: $color-aa;
$color-dark: darken($color-base, 20%);
$color-light: lighten($color-base, 20%);
$color-mixed: mix(#fff, $color-base, 75%);
$color-trans: transparentize($color-base, .5);
// CSS VARIABLES
--theme-color-aa-dark: #{$color-aa-dark};
--theme-color-aa-light: #{$color-aa-light};
--theme-color-aa-trans: #{$color-aa-trans};
--theme-color-aa: #{$color-aa};
--theme-color-dark: #{$color-dark};
--theme-color-light: #{$color-light};
--theme-color-mixed: #{$color-mixed};
--theme-color-trans: #{$color-trans};
--theme-color: #{$color-base};
}
:root {
#include setThemeColors($theme-base, $theme-base-aa);
}
body {
#include themeColor("background","mixed");
font-size: 2rem;
}
ul {
list-style: none; /* Remove default bullets */
}
ul li::before {
content: "\2022"; /* Add content: \2022 is the CSS Code/unicode for a bullet */
#include themeColor("color","dark");
font-weight: bold; /* If you want it to be bold */
display: inline-block; /* Needed to add space between the bullet and the text */
width: 1.2em; /* Also needed for space (tweak if needed) */
margin-left: -.8em; /* Also needed for space (tweak if needed) */
}
li {
#include themeColor("color", "light");
#include themeColor("background", "aa-dark");
}
Why pick one when you can have them both.
_variables.scss
$color0 : white;
$color1 : red;
$color2 : green;
$color3 : blue;
_lists.scss
#use "variables";
#use "sass:map";
#use "sass:meta";
#use "sass:list";
#function dynamic($variable){
$i: 0;
$list: ();
#while(variable-exists($variable + $i)){
$list: list.append($list, map.get(meta.module-variables(variables), $variable + $i));
$i: $i + 1;
}
#return $list;
}
$colors: dynamic('color'); // white red green blue
Import both into your scss files and use the list when you need to loop and the variables for shorthand when applying styles.
map-get is used for getting css value from more kind of object.
suppose you have $param where you have defined multiple properties and now you want to assign. you can use it in following ways -
color: map-get($params, "color");
Where else simple variable holds only single value
map-get to get css value from object holding multiple values whereas
variable to hold single value

Lighten individual background-color with hover by scss - how?

I have some blocks with different background-colors (which are set in variables) and if a user hovers one of them, the color shall light/fade a bit.
Therefore I use this one:
.block1:hover,.block2:hover{
background-color:lighten($color1,40%);
}
But this just fades one static color - $color1 - to 40%. How would I do that, if .block1 had $color1 and .block2 had $color2 as background colors set? So the result should be
.block1:hover{
background-color:lighten($color1,40%);
}
.block2:hover{
background-color:lighten($color2,40%);
}
What do I need to use therefore?
Use a mixin, like so:
.block1 {
.backgroundsetup($color1);
}
.block2 {
.backgroundsetup($color2);
}
.backgroundsetup($color, $amt: 40%) {
background-color: $color;
&:hover {
background-color: lighten($color, $amt);
}
}
There's no special way to write the CSS you have in your example in SCSS, that would be the way you do it. But if you want to optimize and write less code, then you could take advantage of SASS' hashmaps and the foreach loop to do this for you.
SASS
$color1: #4e9bac;
$color2: #248cff;
$color3: #3b5998;
$blocks: (
block1: $color1,
block2: $color2,
block3: $color3,
);
#each $block, $color in $blocks {
.#{$block} {
background-color: $color;
&:hover {
background-color: lighten($color, 40%);
}
}
}
CSS Output
.block1 {
background-color: #4e9bac;
}
.block1:hover {
background-color: #d8eaee;
}
.block2 {
background-color: #248cff;
}
.block2:hover {
background-color: #f0f7ff;
}
.block3 {
background-color: #3b5998;
}
.block3:hover {
background-color: #bbc8e4;
}

How to change a class format based on body's class with SCSS?

I am making a web app that is used in three (or more) different contexts, and I want each context to have a different color scheme. However, I don't want to have to maintain three different stylesheets when all that changes is colors, typically.
For instance, suppose the themes are red, blue, and orange. One of my stylesheets describes the link colors:
a {
color: $some_color;
}
I want to split this based on the class applied to the body:
body.style1 {
a {
color: $red;
}
}
body.style2 {
a {
color: $blue;
}
}
body.style3 {
a {
color: $orange;
}
}
You can see how this gets unwieldy pretty quickly if you're changing the style for lots of elements. Is there a way to do this more like this?
a {
&closest:body.style1 {
color: $red
}
&closest:body.style2 {
color: $blue;
}
&closest:body.style3 {
color: $orange;
}
}
This way I can code my scss in a clearer, more maintainable way.
It appers you don't have to have the & first, so this works (at least in 3.2.10):
a {
body.style1 & {
color: $red
}
body.style2 & {
color: $blue;
}
body.style3 &{
color: $orange;
}
}
This is what I prefer. Define a mixin like body-style :
#mixin body-style($style, $map) {
body.#{$style} & {
#each $property, $value in $map {
#{$property}: $value;
}
}
}
Then use this for every tag by passing $style as style class of body and $map as map of css keys and values.
a {
#include body-style(style1, (
color: red,
background: white
)
);
}
It will return :
body.style1 a {
color: red;
background: white;
}

Resources