Scss nested if statements in a function - css

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; }
}

Related

How to get the square of a value in SCSS mathematically?

Sass doesn't have a power function. So how could I do a power operation like this?
.className {
padding: 2^2; // Should equal 4
}
Any ideas?
You will have to make a function for it something like:
#function power($number, $power) {
$exponent: 1;
#if $power > 0 {
#for $i from 1 through $power {
$exponent: $exponent * $number;
}
} #else if $power < 0 {
#for $i from 1 through $power {
$exponent: $exponent / $number;
}
}
#return $exponent;
}
The credit should go to this guy who made this: https://www.bhalash.com/archives/13544805657

Return Hex Color code with SASS lighten function

How do I return a hex code using the SASS lighten function?
#function returnHexValue($color){
#debug $color;
#if $color == "white" {
#return "#fff";
}
#if $color == "black" {
#return "#000";
}
#return $color;
}
When I use something like returnHexValue(lighten(#000,100%));, I still get the value returned as white instead of #fff.
You can use following function that will force Hex value
#function force-hex($color) {
#if type-of($color) == 'color' {
$hex: str-slice(ie-hex-str($color), 4);
#return unquote("\##{$hex}");
}
#return $color;
}
body{
color: force-hex(lighten(#000,100%));
}
Already there are few request in SASS github project to prevent conversion of Hex to a color value. You can follow below issues
https://github.com/sass/sass/issues/343
https://github.com/sass/sass/issues/363

Sass: function as color in rgba

I created the map with colors and their modifications (light, dark etc) and custom function for getting values from this map.
$colors: (
text: #383838,
cyan: (
base: #54c2e3,
light: lighten(#54c2e3, 15%),
dark: darken(#54c2e3, 15%)
)
)
#function color($color-name, $color-variant:null) {
#if $color-variant != null {
#return map-get(map-get($colors,$color-name),$color-variant);
} #else {
#if type-of(map-get($colors,$color-name)) == 'map' {
#return map-get($colors,'base');
} #else {
#return map-get($colors,$color-name);
}
}
}
But when i put this function inside rgba:
background: rgba(color(cyan), .5);
i get an error
Error: argument `$color` of `rgba($color, $alpha)` must be a color
Is there any possible way to use functions as parameters inside sass rgba function?
Maybe i'm blind, but i couldn't google an answer.
Based on my understanding, the problem was with the value returned by the custom function.
The below line of code within the #if part of the #else condition would actually not return anything based on your settings. You should first get the color's map based on the value passed as argument and then pick the base color value from that map.
#return map-get($colors,base);
So, the correct #return statement should have been like in the below code block.
#function color($color-name, $color-variant:null) {
#if $color-variant != null {
#return map-get(map-get($colors,$color-name),$color-variant);
} #else {
#if type-of(map-get($colors,$color-name)) == 'map' {
#return map-get(map-get($colors,$color-name),base); /* your problem was here */
} #else {
#return map-get($colors,$color-name);
}
}
}
CodePen Demo (the a tag's color and background are set using the output of the function).

How can I zerofill the index of a Sass for loop?

#for $i from 1 through $layer-count {
#layer-#{$i} { background: url('../layers/layer-#{$i}.png'); }
// background images are named layer-0001.png and up
}
There must be a way to achieve this, but I haven't been able to find anything.
You could do something like this:
#function zerofill($i) { #return #{str-slice("0000",0,4 - str-length(#{$i}))}$i; }
#for $i from 1 through $layer-count {
$i: zerofill($i); // now $i holds the zro-filled value for further use
#layer-#{$i} { background: url('../layers/layer-#{$i}.png'); }
}
DEMO
Or the same with a more general function, that takes a length for the zero-filled value:
#function rep($n, $s: "0") {
$out: $s;
#while str-length($out) < $n { $out: $out + $s; }
#return $out;
}
#function zerofill($i, $n) { #return #{rep($n - str-length(#{$i}))}$i; }
DEMO
Note:
To be able to use the string functions you need to run Sass v3.3, so I quickly rewrote the general function so that it works in older Sass versions (I threw in pow() too that is also already integrated in v3.3, so then you could just use the zerofill() part of this):
#function pow($b, $n) {
$f: $b; #while $n > 1 { $f: $f * $b; $n: $n - 1; } #return $f;
}
#function zerofill($i, $n){
$f: pow(10, $n - 1); $out: null;
#while $f >= 1 {
$out: $out#{floor($i / $f)}; $i: $i - floor($i / $f) * $f; $f: $f / 10;
} #return $out;
}
DEMO

Rounding numbers in Sass and adjusting the amount of decimals

Is their a way in sass to change the digit that rounding occurs on, I would like to stop rounding of a number like this 2.0242914979757085% to this 2.024%. I would like to adjust the amount of decimals in the output css
A quick option without any extra functions would be to multiply the number by 1000, then round it, then divide by 1000.
round($percent * 1000) / 1000;
From the SASS change logs:
The numeric precision of numbers in Sass can now be set using the --precision option to the command line. Additionally, the default number of digits of precision in Sass output can now be changed by setting Sass::Script::Number.precision to an integer (defaults to 3). Since this value can now be changed, the PRECISION constant in Sass::Script::Number has been deprecated. In the unlikely event that you were using it in your code, you should now use Sass::Script::Number.precision_factor instead.
This was added in SASS 3.1.8.
You could use the following function, which is a slight improvement of the function created by Takeru Suzuki :
#function decimal-round ($number, $digits: 0, $mode: round) {
$n: 1;
// $number must be a number
#if type-of($number) != number {
#warn '#{ $number } is not a number.';
#return $number;
}
// $digits must be a unitless number
#if type-of($digits) != number {
#warn '#{ $digits } is not a number.';
#return $number;
} #else if not unitless($digits) {
#warn '#{ $digits } has a unit.';
#return $number;
}
#if $digits > 0 {
#for $i from 1 through $digits {
$n: $n * 10;
}
}
#if $mode == round {
#return round($number * $n) / $n;
} #else if $mode == ceil {
#return ceil($number * $n) / $n;
} #else if $mode == floor {
#return floor($number * $n) / $n;
} #else {
#warn '#{ $mode } is undefined keyword.';
#return $number;
}
}
Output :
decimal-round(0.333) => 0
decimal-round(0.333, 1) => 0.3
decimal-round(0.333, 2) => 0.33
decimal-round(0.666) => 1
decimal-round(0.666, 1) => 0.7
decimal-round(0.666, 2) => 0.67
You could also do the following:
#function ceilHundredths($numbers) {
$numbers: $numbers * 10000;
#if ($numbers < 1) {
$numbers: $numbers - 1;
} #else {
$numbers: $numbers + 1;
}
#return round($numbers)/ 100#{"%"};
}
.test--regular {
margin-left: percentage( -1 / 3 );
}
.test {
margin-left: ceilHundredths( -1 / 3 );
}
.test--regular--2 {
margin-left: percentage( 1 / 3 );
}
.test--2 {
margin-left: ceilHundredths( 1 / 3 );
}
Strictly speaking this is not an answer to your question but if you just want to strip decimal places, you might as well just do this:
font-size: round(12.5); /* => 12 */
It may be appropriate with values that do not require a high level of precision, as for example with font sizes.
Here is my sass rounding function
#function round($value, $fractionDigits: 0) {
$power: math.pow(10, $fractionDigits);
#return math.div(math.round($power * $value), $power);
}
Usage:
round(2.0242914979757085%, 3) // 2.024%
Don't forget to add the sass:math module, like so:
#use "sass:math";
P.S. this is a sass port of following JS method I was using:
export const round = (value, fractionDigits = 0) => {
const power = Math.pow(10, fractionDigits);
return Math.round(power * value) / power;
};

Resources