I tried to make the following code look fancier with an #each or a #for loop (without any usable result).
.btn[data-btn-color="black"] {
#include colored-btn($black);
}
.btn[data-btn-color="blue"] {
#include colored-btn($blue);
}
.btn[data-btn-color="red"] {
#include colored-btn($red);
}
// ... and more colors ...
My current approach is to take value from the variable to use it as the value for the data-btn-color attribute and put that snippet into an #each loop.
Something like
#each $color in ($black, $blue) {
#include colored-btn($color);
}
which compiles into:
.btn[data-btn-color="black"] {
background-color: #000; // $black
}
.btn[data-btn-color="blue"] {
background-color: #00f; // $blue
}
Is there any function, which allows me to do such a thing?
You were so close! You don't want the () around what you want to go through in #each. I think Sass would just see what you have as one list item with a two item list inside.
Here is what I think you're trying to do:
$red: #f00;
$blue: #00f;
$black: #000;
$colors: red $red, blue $blue, black $black;
#mixin colored-button($background-color: #000){
background-color: $background-color;
}
#each $color in $colors {
$name: nth($color, 1);
$hex: nth($color, 2);
.btn[data-btn-color="#{$name}"]{
#include colored-button($hex);
}
}
Which would result in:
.btn[data-btn-color="red"] {
background-color: red; }
.btn[data-btn-color="blue"] {
background-color: blue; }
.btn[data-btn-color="black"] {
background-color: black; }
Related
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(); }
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.
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
I'm refactoring some of my Sass code and I came across a weird issue. My code currently looks like this:
// household
$household_Sector: 'household';
$household_BaseColor: #ffc933;
// sports
$sports_Sector: 'sports';
$sports_BaseColor: #f7633e;
// the mixin to output all sector specific css
#mixin sector-css($sector_Sector,$sector_BaseColor) {
.sector-#{$sector_Sector} {
&%baseColor {
background-color: $sector_BaseColor;
}
}
}
// execute the mixin for all sectors
#include sector-css($household_Sector, $household_BaseColor);
#include sector-css($sports_Sector, $sports_BaseColor);
.product-paging {
h2 {
#extend %baseColor;
}
}
DEMO
The compiled result looks like this:
.product-paging h2.sector-household {
background-color: #ffc933;
}
.product-paging h2.sector-sports {
background-color: #f7633e;
}
But what I need is this:
.sector-household.product-paging h2 {
background-color: #ffc933;
}
.sector-sports.product-paging h2 {
background-color: #f7633e;
}
What I don't understand is why my placeholder (&%baseColor) isn't attached to the parent selector (&%baseColor) as I added the ampersand right in front of it?
Is this maybe a bug when combining & and %? Is there another solution on how to achieve what I want?
EDIT
Alright I figured out why this isn't possible. Anyway is there a workaround for what I'd like to achieve?
Extends, as you've already discovered, can get rather messy. I would go about solving your problem by using an #content aware mixin in combination with global variables (this uses mappings, which are part of 3.3... you can do it with lists of lists, but it's a little less elegant):
$base-color: null; // don't touch
$accent-color: null; // don't touch
$sections:
( household:
( base-color: #ffc933
, accent-color: white
)
, sports:
( base-color: #f7633e
, accent-color: white
)
);
// the mixin to output all sector specific css
#mixin sector-css() {
#each $sector, $colors in $sections {
$base-color: map-get($colors, base-color) !global;
$accent-color: map-get($colors, accent-color) !global;
&.sector-#{$sector} {
#content;
}
}
}
.product-paging {
#include sector-css() {
h2 {
background-color: $base-color;
}
}
}
Output:
.product-paging.sector-household h2 {
background-color: #ffc933;
}
.product-paging.sector-sports h2 {
background-color: #f7633e;
}
Update: Since you want to guarantee that the sector class is always at the top, you just need to switch around a little.
#mixin sector-css() {
#each $sector, $colors in $sections {
$base-color: map-get($colors, base-color) !global;
$accent-color: map-get($colors, accent-color) !global;
.sector-#{$sector} {
#content;
}
}
}
#include sector-css() {
&.product-paging {
h2 {
background-color: $base-color;
}
h3 {
background-color: #CCC;
}
h2, h3 {
color: $accent-color;
}
}
}
I'm trying to loop through a list of values in Sass and use interpolation of the current key to dynamically output class names that utilize #include and #extend, respectively.
Here is a pen showing the problem, simplified. http://codepen.io/ghepting/pen/vBmLy
As you can see in the markup, I have tried including the "_" inside of the interpolated string as well as outside of it. Is there something I'm missing to work around this limitation of how Sass supports interpolation?
(Note: the OP's pen has disappeared. This is not the original code found in the pen, but a rough approximation of the problem)
$error-light: red;
$error-dark: darken(red, 10%);
$success-light: green;
$success-dark: darken(green, 10%);
$dialogs: error, success;
#each $d in $dialogs {
.#{$d} {
background: $#{$d}-light;
}
}
Interpolation doesn't work on mixins or variables at this point in time. You'll have to come up with a different way to achieve your goal.
As of Sass 3.3, you can use mappings for this purpose for variables:
$dialogs:
( error:
( light: red
, dark: darken(red, 10%)
)
, success:
( light: green
, dark: darken(green, 10%)
)
);
#each $name, $colors in $dialogs {
.#{$name} {
color: map-get($colors, dark);
}
}
And for functions:
#function green() {
#return lighten(green, 10%);
}
#function red() {
#return lighten(red, 10%);
}
#mixin my-bg($function-name) {
background: call($function-name);
}
.foo {
#include my-bg('red');
}
Alternative workaround (for a particular use case):
https://sass-lang.com/documentation/at-rules/mixin#passing-arbitrary-arguments
💡 Fun fact:
Because an argument list keeps track of both positional and keyword arguments, you use it to pass both at once to another mixin. That makes it super easy to define an alias for a mixin!
If you are interested in mixin interpolation because you have a group of mixins, like this:
//_mixins.scss
#mixin text-style-1($args...){ //sass here }
#mixin text-style-2($args...){ //sass here }
#mixin text-style-3($args...){ //sass here }
//_text.scss
.text-style-1 {
#include text-style-1;
}
.text-style-1-contrast {
#include text-style-1($contrast: true);
}
.text-style-2 {
#include text-style-2;
}
.text-style-2-contrast {
#include text-style-2($contrast: true);
}
We can take advantage of passing arbitrary arguments and use an alias for the group:
//_mixins.scss
#mixin text-style-1($args...){ //sass here }
#mixin text-style-2($args...){ //sass here }
#mixin text-style-3($args...){ //sass here }
#mixin text($mixin, $args...) {
#if $mixin == 'style-1' { #include text-style-1($args...); }
#else if $mixin == 'style-2' { #include text-style-2($args...); }
#else if $mixin == 'style-3' { #include text-style-3($args...); }
}
//_text.scss
$text-styles: 'style-1', 'style-2', 'style-3';
#each $style in $text-styles {
.text-#{$style} {
#include text($style);
}
.text-#{$style}-contrast {
#include text($style, $contrast: true);
}
}
Ran into this issue of trying to include an interpolated variable inside a mixin and was able to resolve it with placeholders:
%color-scheme-dark-bg-1 { background-color: #4e5163; }
%color-scheme-dark-color-1 { color: #4e5163 !important; }
%color-scheme-light-bg-1 { background-color: #c7c8ce; }
%color-scheme-dark-bg-2 { background-color: #fd6839; }
%color-scheme-dark-color-2 { color: #fd6839 !important; }
%color-scheme-light-bg-2 { background-color: #fecfc1; }
.card_color {
#mixin CardColorScheme($arg: 1) {
.borderPercent {
#extend %color-scheme-dark-bg-#{$arg};
}
.border {
#extend %color-scheme-light-bg-#{$arg};
}
ul li:before {
#extend %color-scheme-dark-color-#{$arg};
}
.percent {
#extend %color-scheme-dark-color-#{$arg};
}
.heading {
#extend %color-scheme-dark-color-#{$arg};
}
}
&--scheme {
&-1 {
#include CardColorScheme(1);
}
&-2 {
#include CardColorScheme(2);
}
}
}
Hat tip to: https://krasimirtsonev.com/blog/article/SASS-interpolation-in-a-name-of-variable-nest-variables-within-variables