How to count Sass mixin variable arguments - css

I am trying to write a SASS mixin that outputs something different depending on how many variable arguments there are. Is there a way to count the number of arguments passed to a mixin?
#mixin my_func( $args... ) {
#if count($args) === 4 {
... output here ...
}
#else {
... output here ...
}
}

You can use the length function:
#mixin my_func( $args... ) {
#if length($args) == 4 {
... output here ...
}
#else {
... output here ...
}
}

Related

Gaps in sass css output

I'm writing some sass to generate a set of icons based on a series of parameters. I have a function that analyses a set of variables and then returns a 'scenario' variable which in turn is used to filter the information taken from the nested map where everything is stored.
The code which retreives the information from the nested map is as follows:
#each $key-lv0, $lv0 in $icon-config {
#if($key-lv0 == $scenario) {
.icon{
#each $key-lv1, $lv1 in $lv0 {
#if type-of($lv1) != "map" {
#{$key-lv1}: $lv1;
}
#each $key-lv2, $lv2 in $lv1 {
#if type-of($lv2) != "map" {
.#{$key-lv1} {
#{$key-lv2}: $lv2;
}
}
#each $key-lv3, $lv3 in $lv2 {
#if($key-lv2 == "hover") {
.#{$key-lv1}:#{$key-lv2} {
#{$key-lv3}: $lv3;
}
} #else {
.#{$key-lv1} #{$key-lv2} {
#{$key-lv3}: $lv3;
}
}
}
}
}
}
}
}
... and this produces something along these lines:
.icon .icon-header {
background-color: #00a9f0;
}
.icon .icon-header:hover {
border-color: #040100;
}
... etc ...
... which is fine - repeated statements aside whicvh I'll deal with later.
The problem is the cap between ".icon" and ".icon-header". These classes will all be used in a single element and for the css to be interpretted correctly it needs to generate something like this:
.icon.icon-header {
background-color: #00a9f0;
}
.icon.icon-header:hover {
border-color: #040100;
}
I've tried bringing ".icon" down like so:
#if type-of($lv1) != "map" {
.icon#{$key-lv1}: $lv1;
}
and removing it from the top but sass rejects this with the following error:
Error: Properties are only allowed within rules, directives, mixin includes, or other properties.
It seems such a minor thing but it's nagging me and I can't seem to find an answer.

SASS functions check if value is map returns error

I want to check if the value provides to a function is a map or not.
#function func($props...) {
#if(is-map($props)) {
#return 'something';
}
#else {}
}
h1 {
color: func((color: red));
}
I'm getting the error:
(color: red) isn't a valid CSS value.
What am I doing wrong?
I personally never heard about any native Sass function called is-map. If you want to check the type of something, use the type-of function, so for example, checking for type-of($props) == map would solve your problem in this case.
#function func($props...) {
#if(type-of($props) == map) {
#return 'something';
}
#else {}
}
Because function returns map. Not a color as expected. Use map-get to get the access to properties values.
#return map-get($props, color);
And you have the variable argument. To get the first of arguments use nth($props, 1).
Sassmeister demo.
Update
If parameters in map are dynamic you can use this mixin instead of function.
#mixin print($declarations) {
#if $declarations {
#each $property, $value in $declarations {
#{$property}: $value
}
} #else {
#error "mixin print: $declarations is not specified";
}
}
Mixin sassmeister demo.

Sass each function is compiling with dollar sign in front of it

I'm trying to use an each loop in Sass but the css is compiling with the variable name instead of the content of the variable.
$green-1: #9ae200;
$green-2: #5ea600;
$color-list: green-1 green-2;
#each $single-color in $color-list {
&.#{$single-color} {
background-color: $single-color;
}
}
The output I am looking for is:
.green-1 {
background-color:#9ae200;
}
.green-2 {
background-color:#5ea600;
}
But the css is compiling as:
.green-1 {
background-color:green-1;
}
.green-2 {
background-color:green-2;
}
So to try to get the dollar sign in there I tried this:
#each $single-color in $color-list {
#function create-variable($variable){
#return "$" + $variable;
}
&.#{$single-color} {
background-color: create-variable($single-color);
}
}
But that compiled as:
.green-1 {
background-color:$green-1;
}
.green-2 {
background-color:$green-2;
}
Sass is not reading the variables for some reason and is taking them literally. Anyone know how to make this work?
You cannot create dynamic variable in sass. Instead you can achieve your desired result using map
example:
$green-1: #9ae200;
$green-2: #5ea600;
$color-map: (
green-1: $green-1,
green-2: $green-2,
);
.body{
#each $key,$value in $color-map {
&.#{$key} {
background-color: $value;
}
}
}

Scss nested if statements in a function

I want to pass two values into a function "sprite-chooser()" so that I can choose which sprite to load if it's on a light or dark background. Before I load the sprite I need to check for which UI it is first - so I've got two #if statements and nested #if statements inside but get an error saying: Syntax error: Function sprite-chooser finished without #return.
#function sprite-chooser($ui-for, $bg-color) {
#if ($ui-for == "ui-1") {
#if (lightness( $bg-color ) > 60 and $ui-for == "ui-1") {
#return #{$sprite-dark-ui-1};
}
#else {
#return #{$sprite-light-ui-1};
}
}
#else if ($ui-for == "ui-2") {
#if (lightness( $bg-color ) > 60 and $ui-for == "ui-2") {
#return #{$sprite-dark-ui-2};
}
#else {
#return #{$sprite-light-ui-2};
}
}
}
$background-color: #fff;
.class-name {
background: url(sprite-chooser("ui-1", $background-color)) 0 0 no-repeat;
}
You need another else case
...
#else if ($ui-for == "ui-2") {
#if (lightness( $bg-color ) > 60 and $ui-for == "ui-2") {
#return #{$sprite-dark-ui-2};
}
#else {
#return #{$sprite-light-ui-2};
}
}
#else { #return null; }
}

Pass function or mixin by reference in SASS

Is there any way to pass a function or a mixin by reference to another function or mixin in SASS, and then call the referenced function or mixin?
For example:
#function foo($value) {
#return $value;
}
#mixin bob($fn: null) {
a {
b: $fn(c); // is there a way to call a referenced function here?
}
}
#include bob(foo); // is there any way I can pass the function "foo" here?
Functions and mixins are not first-class in Sass, meaning you can't pass them around as arguments like you can with variables.
Sass 3.2 and older
The closest you can get is with the #content directive (Sass 3.2+).
#mixin foo {
a {
#content;
}
}
#include bob {
b: foo(c); // this replaces `#content` in the foo mixin
}
The only caveat is that the #content can't see what's inside your mixin. In other words, if c was only defined inside the bob mixin, it essentially wouldn't exist because it isn't considered in scope.
Sass 3.3 and newer
Starting with 3.3, you can use the call() function, but it is only for use with functions, not mixins. This requires passing string containing the name of the function as the first argument.
#function foo($value) {
#return $value;
}
#mixin bob($fn: null) {
a {
b: call($fn, c);
}
}
#include bob('foo');

Resources