Using variables for CSS properties in Sass - sass

I am writing a #mixin with some math in it that calculates the percentage width of an element, but since it is very useful I would like to use the same function for other properties too, like margins and paddings.
Is there a way to pass the property name as an argument to a mixin?
#mixin w_fluid($property_name, $w_element,$w_parent:16) {
$property_name: percentage(($w_element/$w_parent));
}

You need to use interpolation (eg. #{$var}) on your variable in order for Sass to treat it as a CSS property. Without it, you're just performing variable assignment.
#mixin w_fluid($property_name, $w_element, $w_parent:16) {
#{$property_name}: percentage(($w_element / $w_parent));
}

In addition to the #rcorbellini response
You can use string and variable together
#mixin margin($direction) { // element spacing
margin-#{$direction}: 10px;
}

Related

How to use functions in :root in SCSS for custom properties?

I'm trying to generate custom properties in the :root using SCSS. I have a function called fluidClamp() that generates a clamp function for text sizes. It accepts a minimum value and a maximum value.
However, I can't get any functions to work in SCSS when they're used inside :root{}.
For example:
:root {
--text-s: fluidClamp(1.4, 1.6);
--text-m: fluidClamp(1.6,1.8);
}
It completely ignores the function, even though the function works everywhere else. What are my options?
You can't use function in your :root pseudo element.
To achive your goal, you need to declare in your :root the basic rules, like:
$text_s: 1.4;
$text_m: 1.6;
:root{
--text-s: $text_s;
--text-m: $text_m;
}
Then in your component you can call:
.myClass{
font-size: fluidClamp(var(--text-s), var(--text-m))
}
Hope it help.

Scss function returns no calculated value

I am working on a mixin for breakpoints and I have the following issue.
when a specific state (mode for max-width) is set then the breakpoint should be recalculated by extracting one em value (1px/16 (default font size)).
This is the important part of my code (I might get rid of the function, basically this can be done inline):
$mediaBreakpoint: map-get( $breakpoints, $breakpoint );
// if the mode is for max-width then subtract 1px.
#if map-get( $modes, $mode ) == 'max-width' {
$mediaBreakpoint: calculateMaxWidth(#{$mediaBreakpoint})
}
#debug $mediaBreakpoint;
/**
* calculate the max width based on input
*/
#function calculateMaxWidth($breakpoint){
$newBreakpoint: calc( #{$breakpoint} - 0.0625em ); // 1px in em sizing.
#return $newBreakpoint;
}
But whatever I try, the #debug value shows as:
48em-0.0625em // this is invalid, I need the actual outcome (in this case 47.9375) .
64em // valid min-width
This is the compiled css:
#media screen and (max-width: calc( 48em - 0.0625 )) {
}
What am I missing?
I found the answer myself after a lot of debugging. At first I misunderstood the interpolation. After reading the docs in depth I noticed that I should have wrapped the whole calculation instead of just the variable because I am working inside the map expression.
Quoted from the official Sass docs:
Interpolation can be used almost anywhere in a Sass stylesheet to embed the result of a SassScript expression into a chunk of CSS.
I changed my function to calculate like this and then the mixin started working. hooray!
$newBreakpoint: #{$breakpoint - 0.0625em};

Sass: rgba function is not working as per documentation

I have two examples that I'm trying to solve:
Example 1
$test: #101E41
body
--colors-dim: rgba(#{$test}, 0.64)
Output: rgba(#101E41, 0.64)
Example 2
body
--colors-active: #101E41
--colors-dim: rgba(var(--colors-active), 0.64)
Output: rgba(var(--colors-active), 0.64)
Both of these look like are examples that should be valid as shown here: https://sass-lang.com/documentation/modules#rgb
Is there something I'm missing?
You need to make use of interpolation to use Sass inside CSS Custom Properties
CSS custom properties, also known as CSS variables, have an unusual declaration syntax: they allow almost any text at all in their declaration values. What’s more, those values are accessible to JavaScript, so any value might potentially be relevant to the user. This includes values that would normally be parsed as SassScript.
Because of this, Sass parses custom property declarations differently than other property declarations. All tokens, including those that look like SassScript, are passed through to CSS as-is. The only exception is interpolation, which is the only way to inject dynamic values into a custom property.
$bar: #900;
:root {
--foo: #{rgba($bar, 0.5)};
}
Results in:
:root {
--foo: rgba(153, 0, 0, 0.5);
}
For your second example, you're going to have to get a little... creative... since Sass will bail and ignore any CSS Custom Property syntax it sees, you can't make use of Sass's rgba function with Custom Properties - the Sass compiler won't resolve the values for you.
Thankfully, you can still use the native CSS rgba function with Custom Properties, the only downside is that you'll need to break your hexadecimal value into its R, G, and B values.
#function toRGB($color)
#return red($color), green($color), blue($color)
$bar: #900
:root
--foo: #{$bar}
--foo-rgb: #{toRGB($bar)}
--foo-dim: #{rgba($bar, 0.5)}
--foo-dim: rgba(var(--foo-rgb), 0.5)
.button
background-color: var(--foo-dim)
Compiles to:
:root {
--foo: #900;
--foo-rgb: 153, 0, 0;
--foo-dim: rgba(153, 0, 0, 0.5);
--foo-dim: rgba(var(--foo-rgb), 0.5);
}
.button {
background-color: var(--foo-dim);
}
https://www.sassmeister.com/gist/39ffc57c492de73066831afe5a9696f6

SASS Functions with Variables

I'm fairly new to SASS functions and mixins. I would like to make a SASS function that multiplies a base spacing unit variable based on the number that is provided in the class name.
It would work like this. Say you had a variable called $base-spacing-unit with a value of 10. If you put the class ".pad-top-b5" on an HTML element it would give it a top padding of the $base-spacing-unit x 5.
The function might look something like this:
$base-spacing-unit: 10;
#function pad-top-b($val) {
padding-top: ($base-spacing-unit * $val);
}
On the HTML element you could put a class like this:
<div class="pad-top-b10"></div>
And the element would have a top padding of 100px. Is this even possible with SASS?
You can use a #for loop that generates a set of classes:
$class-slug: pad-top-b;
$base-spacing-unit: 10;
$classes-amount: 10;
#for $i from 1 through $classes-amount {
.#{$class-slug}#{$i} {
padding-top: ($base-spacing-unit * $i);
}
}
Demo on SassMeister.

SASS for each interpolation error when export css in compressed mode

I have a map declared like below
Map Definition
$color-array:(
black:#4e4e4e,
blue:#0099cc,
dark-blue:#14394e,
green:#2ebc78,
white:#ffffff,
orange:#ed6a0e
);
and calling the same in for each loop to generate class for text color and background color like below
#each $color-name, $color-value in $color-array{
.#{$color-name}{
color: $color-value !important;
}
.bg-#{$color-name}{
background: $color-value !important;
}
}
I am using gruntjs for for compilation, when i set output style to compressed it gives below error
You probably don't mean to use the color value #000' in interpolation
here. It may end up represented as #000000, which will likely produce
invalid CSS. Always quote color names when using them as strings (for
example, "#000"). If you really want to use the color value here, use
"" + $color-name'.
Error: Invalid CSS after ".": expected class name, was "#000"
on line 25 of SCSS/_base.scss
from line 5 of scss/style.scss
But when i set output style to expanded it runs fine.
In your colors array, change all the key double-quoted string keys and things should work.
$color-array:(
"black":#4e4e4e,
"blue":#0099cc,
"dark-blue":#14394e,
"green":#2ebc78,
"white":#ffffff,
"orange":#ed6a0e
);
An alternative of changing the SCSS code would be to make sure the variable is a string like the error message mentioned
#each $color-name, $color-value in $color-array{
.#{"" + $color-name}{
color: $color-value !important;
}
.bg-#{"" + $color-name}{
background: $color-value !important;
}
}

Resources