Trigonometric functions in Sass -- preprocessor error - css

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.

Related

Scss how convert string to numeric value

I want to perform mathematical operations using the font-size information with the function below. I remove the rem unit information of $font-size using the sass build-in string functions, but then I cannot perform mathematical operations because the value type is string.
Is there a way to convert a string value type to numeric value type in sass?
#use "../abstracts/variables" as *;
#use "sass:math";
#function em($value, $font-size) {
$length: str-length(#{$font-size}); //sample-think about it font-size 1.125rem
$trim: ($length - 3);
$data: str-slice(#{$font-size}, 1, $trim);
$result: math.div($value, $data);
#return $result + "em";
}
It would probably be better to use a helper function to remove the unit of $font-size such as this one.
#function stripUnit($number) {
#if meta.type-of($number) == "number" and not math.is-unitless($number) {
#return math.div($number, $number * 0 + 1);
}
#return $number;
}
#function em($value, $font-size) {
$data: strip-unit($font-size);
$result: math.div($value, $data);
#return $result + "em";
}

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

sass convert px to vw

I found a tutorial on how to write function that converts pixels to vw:
#function get-vw($target) {
$vw-context: (1000*.01) * 1px;
#return ($target/$vw-context) * 1vw;
}
usage on tutorial:
.headline {
font-size: get-vw(72px);
}
but when I use it like its explained nothing happens
my browser returns:
font-size: get-vw(44px); Invalid property value
Since I don't need learn sass at this moment but need only way to convert px to vw can someone help me to make this work?
#function vw($px-vw, $base-vw: 1292px)
#return ($px-vw * 100vw) / $base-vw
.container
font-size: vw(16px)
You can try this:
1. Create a function
$vw-viewport: 1920;
#function get-vw($font){
$vw-context: $vw-viewport * 0.01 * 1px;
#return $font / $vw-context * 1vw;
#return $font;
}
2. Apply the function
.font20{
font-size: get-vw(20px);
}
Did you test this?
#use "sass:math"; //You can use "sass:math"
$vw-viewport: 1920;
#function get-vw($font){
$vw-context: $vw-viewport * 0.01 * 1px;
#return math.div($font, $vw-context) * 1vw;
}
The above didn't work for me but this did :
#function strip-unit($number) {
#if type-of($number) == 'number' and not unitless($number) {
#return $number / ($number * 0 + 1);
}
#return $number;
}
#function get-vw($px-vw, $base-vw: 1920px){
#return #{strip-unit($px-vw) * 100 / strip-unit($base-vw)}vw;
}

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