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

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

Related

How to count Sass mixin variable arguments

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

Trigonometric functions in Sass -- preprocessor error

Unfortunately, I think I misunderstand how to use trigonometric functions in Sass. I've done a fair amount of google search, but with limited results.
In order to animate the transition of an HTML element I have code similar to the following in one of my scss files:
#home-positions {
transform: translateX(200px * sin(45deg));
}
When my Sass is compiling, however, I get the following error:
Syntax error: Undefined operation: "200px times sin(45deg)".
It is very liking I am missing something fundamental, probably pretty simple, and syntactic. Unfortunately, I've looked at a bunch of examples of trigonometric function uses in Sass, though, and I haven't been able to spot the difference between my code, and that in the examples.
The following solution is extracted from Trigonometry In Sass by Daniel Perez Alvarez.
/* power */
#function pow($number, $exp) {
$value: 1;
#if $exp > 0 {
#for $i from 1 through $exp {
$value: $value * $number;
}
}
#else if $exp < 0 {
#for $i from 1 through -$exp {
$value: $value / $number;
}
}
#return $value;
}
/* factorial */
#function fact($number) {
$value: 1;
#if $number > 0 {
#for $i from 1 through $number {
$value: $value * $i;
}
}
#return $value;
}
/* pi */
#function pi() {
#return 3.1415926535897932384626433832795028841971694;
}
/* radian */
#function rad($angle) {
$unit: unit($angle);
$unitless: $angle / ($angle * 0 + 1);
// If the angle has 'deg' as unit, convert to radians.
#if $unit == deg {
$unitless: $unitless / 180 * pi();
}
#return $unitless;
}
/* sine */
#function sin($angle) {
$sin: 0;
$angle: rad($angle);
// Iterate a bunch of times.
#for $i from 0 through 10 {
$sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
}
#return $sin;
}
And then eventually
#home-positions {
transform: translateX(200px * sin(45deg));
}
To anyone confused by this in the future, Sass itself, as of 11/17/14 does not support trigonometric functions. Instead, the Compass framework is required to use them. (See this article for step-by-step instructions on installing compass.)
Or just
$sin45deg: .7071;
Then replace sin(45deg) with $sin45deg. Tada, no framework needed.

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

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