sass using variable as mixin data - css

I'm using grid from csswizardry and wanting to create breakpoints as variables...
If defined as standard "strings":
$breakpoints: (
'palm' '(max-width: 480px)'
)!default;
But when I change it to:
$palmmaxwidth: 480px;
$breakpoints: (
'palm' '(max-width: $palmmaxwidth)'
)!default;
it will not compile correctly within the mixin:
#mixin grid-media-query($media-query){
$breakpoint-found: false;
#each $breakpoint in $breakpoints{
$name: nth($breakpoint, 1);
$declaration: nth($breakpoint, 2);
#if $media-query == $name and $declaration{
$breakpoint-found: true;
#media only screen and #{$declaration}{
#content;
}
}
}
#if $breakpoint-found == false{
#warn "Breakpoint ‘#{$media-query}’ does not exist"
}
}
The error is Invalid CSS after "...nd (max-width: ": expected expression (e.g. 1px, bold), was "$palmmaxwidth)"
What am I missing?

The solution is quite simple after trying every possible combination:
$breakpoints: (
'palm' '(max-width: '+$palmmaxwidth+')'
)!default;

Related

SASS mixin outputs function in compiled CSS

My compiled CSS when viewed has a SASS function in it that was never compiled. This is presumably caused by the mixin I'm using to auto generate classes. I have no idea how to fix it.
SASS code:
$rsColors: (
main: (
base: #333030,
lighter:#827a7a,
light:#5a5555,
dark:#0c0b0b,
darker:#000000,
red: #211010,
accent:#999595,
border: #666666
),
link: (
base: #c42727,
lighter:#eb9999,
light:#de5959,
dark:#841a1a,
darker:#440e0e,
hover:#841a1a,
bg:rgba(80, 80, 80, 0.8),
bgHover: #cccccc
)
}
#mixin modifiers($map, $attribute, $prefix: '-', $hover: 'false', $separator: '-',$base: 'base', $type: 'darken', $perc: '15%') {
#each $key, $value in $map {
&#{if($key != $base, #{$prefix}#{$key}, '')} {
#if type-of($value) == 'map' {
#include modifiers($value, $attribute, $separator, $hover);
}
#else {
#{$attribute}: $value;
#if $hover == 'true' {
&:hover {
$function: get-function($type);
#{$attribute}: call($function,$value,$perc);
}
}
}
}
}
}
.rsBg {
#include modifiers($rsColors, 'background', $hover: 'true');
}
Compiled CSS (as viewed from style editor in Firefox inspector):
...
.rsBg-yellow-700 {
background: #b7791f;
}
.rsBg-yellow-700:hover {
background: darken(#b7791f, 15%);
}
...
How can I fix the compiled CSS so it's rendered correctly? I figure the mixin is to blame since it's outputting what I'm telling it to. Why it's not compiling before being output to CSS?
Expected Output:
...
.rsBg-yellow-700 {
background: #b7791f;
}
.rsBg-yellow-700:hover {
background: #915300; //assuming 15% darken
}
...
**Edit**
After some testing I have found I needed to add the ```get-function()``` method to get ```call()``` to work. However, no matter what I try I can not get the ```$perc``` variable in such a way as to not throw a "not a number" error. I can hard code percentages and it will compile without errors.. but I'd rather not have to do that.
The problem actually comes from the way you call the function and not the mixin. Instead of:
#{$attribute}: unquote(#{$type}($value, #{unquote($perc)}));
You should use the built-in function call() as below:
#{$attribute}: call($type, $value, $perc);
You also need to remove the quotation marks for the parameter $perc or you will get an error such as: $amount: "15%" is not a number for 'darken'. I tried to remove them with unquote() but it doesn't seem to work.
The answer to this issue was the use of '' in the arguments. Specifically the $lightness variable (which was changed from the #perc variable). Once I removed the quotes and just let it hang there, everything compiled and worked fine.
I removed the $type variable and changed the function to scale_color as it seemed to fit better with what I wanted. I should probably change the argument variable to a different name so not to be confused with the scale_color() argument. A task for a different day though.
PLEASE NOTE: I am accepting #Arkellys answer because it set me on the right path to this answer, and I feel really weird about accepting my own answer. I just added this answer so if another comes along it might help. Thank you #Arkellys for your help!
The final mixin
#mixin modifiers($map, $attribute, $prefix: '-', $hover: 'false', $separator: '-',$base: 'base', $lightness: -15%) {
#each $key, $color in $map {
&#{if($key != $base, #{$prefix}#{$key}, '')} {
#if type-of($color) == 'map' {
#include modifiers($color, $attribute, $separator, $hover);
}
#else {
#{$attribute}: $color;
#if $hover == 'true' {
&:hover {
#{$attribute}: scale_color($color,$lightness: $lightness);
}
}
}
}
}
}
.rsBg {
#include modifiers($rsColors, 'background', $hover: 'true', $lightness: -20%);
}

Scalable, global variable assignment #mixin for Sass

I thought that I had already solved this, but the code is not compiling in the way that I intend.
Here is my current code:
$prefix: 'foo';
#mixin var-assign($var, $val) {
$var: $val !global;
};
// will output .foo-selector
.#{$prefix}-selector {
/* ... */
}
#include var-assign($prefix, 'bar');
// should output .bar-selector
.#{$prefix}-selector {
/* ... */
}
The code above prints .foo-selector twice. Where am I going wrong that I am not printing one instance of .foo-selector ad one instance of .bar-selector?
You need to changes in your mixin variable, Try using
#mixin var-assign($prefix, $val) {
$prefix: $val !global;
};
Working example here:

SASS - Passing collection to sass mixin as an argument

How to pass collection to a sass mixin ?
=media($type1, $size1: null)
#if ($type1) and ($size1)
#media ($type1: $size1)
#content
#elseif ($type1) and not ($size1)
$collection: $type1
#media (nth($collection, 1): nth($collection, 2)) <-- ERROR
#content
#else
#error "Upsss...."
Use case
$m: "36em"
$minw: "min-width
$tablet: ("type1": $minw, "size1": $m)
+media($tablet) <-- ERROR
p
font-size: 2em
Sorted. I had to use #{map-get($collection, $key-name)} function
=media($type1, $size1: null)
#if ($type1) and ($size1)
#media ($type1: $size1)
#content
#elseif ($type1) and not ($size1)
$collection: $type1
#media (#{map-get($collection, "type1")}: #{map-get($collection, "size1")})
#content
#else
#error "Upsss...."

Variable interpolation for a media query property in less - missing closing ")"

I'm trying to "translate" a sass function into a less function.
Here is the original SASS one :
#mixin bp($feature, $value) {
// Set global device param
$media: only screen;
// Media queries supported
#if $mq-support == true {
#media #{$media} and ($feature: $value) {
#content;
}
// Media queries not supported
} #else {
#if $feature == 'min-width' {
#if $value <= $mq-fixed-value {
#content;
}
} #else if $feature == 'max-width' {
#if $value >= $mq-fixed-value {
#content;
}
}
}
}
And here is the function I started to make in less as it seems every declaration can not be implemented the same as in sass :
.bp(#feature; #val) when (#mq-support = true) {
#med: ~"only screen";
#media #{med} and (#{feature}:#val) {
#content;
}
}
When I'm compiling this, I got the following error :
Missing closing ')' on line 15, column 34:
15 #media #{med} and (#{feature}:#val) {
16 #content;
So this error seems to come from the closing #{feature} closing bracket but following the documentation and several blog posts on the internet, it seems that since the 1.6.0 version of less, the css property interpolation is a feature that should work.
Does anybody have an idea of what could be wrong here ?
Is it actually possible to use a variable as a property in a media query ?
Maybe I'm doing it totally wrong but it seems the mixins guard feature in less does not work exactly the same as with SASS and the #if condition so the "translation" is a little bit different.
Thank you in advance
Sébastien
Interpolation or using variables in media queries work slightly differently in Less.
First of all, you shouldn't use the normal interpolation syntax (#{med}). Instead it should just be #med.
Next the second condition should also be set to a variable and then appended to the media query just like the #med variable or it should be included as part of the #med variable itself. I've given a sample for both approaches below.
.bp(#feature; #val) when (#mq-support = true) {
#med: ~"only screen and";
#med2: ~"(#{feature}:#{val})";
#media #med #med2{
#content();
}
}
or
.bp(#feature; #val) when (#mq-support = true) {
#med: ~"only screen and (#{feature}:#{val})";
#media #med {
#content();
}
}
Below is a sample conversion of that Sass code completely into its Less equivalent. Less does not support the #content like in Less, so it should be passed as a detached ruleset with the mixin call.
#mq-support: true;
#mq-fixed-value: 20px;
.bp(#feature; #val; #content) {
& when (#mq-support = true) {
#med: ~"only screen and (#{feature}:#{val})";
#media #med {
#content();
}
}
& when not (#mq-support = true) {
& when (#feature = min-width) {
& when (#val <= #mq-fixed-value){
#content();
}
}
& when (#feature = max-width) {
& when (#val >= #mq-fixed-value){
#content();
}
}
}
}
a{
.bp(max-width, 100px, { color: red; } );
}
b{
.bp(min-width, 10px, { color: blue; } );
}

What does the $foo: ("bar": baz, ...); syntax mean in SASS?

Google Materialize defines their color variables in this file like so:
$red: (
"lighten-5": #FFEBEE,
"lighten-4": #FFCDD2,
"lighten-3": #EF9A9A,
"lighten-2": #E57373,
"lighten-1": #EF5350,
"base": #F44336,
"darken-1": #E53935,
"darken-2": #D32F2F,
"darken-3": #C62828,
"darken-4": #B71C1C,
"accent-1": #FF8A80,
"accent-2": #FF5252,
"accent-3": #FF1744,
"accent-4": #D50000
);
I would like to use the colors with something like this:
.light-red-border {
border: 1px solid $red-lighten-1;
}
How do I call those variables directly? They're used in other I can't find anything on this syntax mentioned anywhere.
Edit: I looked around a bit more in the Materialize Github and found some examples in _variables.scss:
$primary-color: color("materialize-red", "lighten-2") !default;
$primary-color-light: lighten($primary-color, 15%) !default;
$primary-color-dark: darken($primary-color, 15%) !default;
However, if you can direct me to an article discussing the syntax used to define the variables I would greatly appreciate it.
You're looking for map-get($red, 'lighten-5'); if you simply want the corresponding value from this map.
To expand on #weirdpanda's answer, these SASS maps need to be iterated upon, which then compiles into more CSS rules.
In the file you linked to, each of those colors is placed in a larger map of $colors:
$colors: (
"materialize-red": $materialize-red,
"red": $red,
"pink": $pink,
"purple": $purple
//...
);
This colors map is then iterated upon, producing matching class selectors like red.lighten-5 in the CSS.
#each $color_name, $color in $colors {
#each $color_type, $color_value in $color {
#if $color_type == "base" {
.#{$color_name} {
background-color: $color_value !important;
}
.#{$color_name}-text {
color: $color_value !important;
}
}
#else {
.#{$color_name}.#{$color_type} {
background-color: $color_value !important;
}
.#{$color_name}-text.text-#{$color_type} {
color: $color_value !important;
}
}
}
}
To actually use these variables within SASS files (for instance, after importing _color.scss, you can access a map value with map-get($map, $key). For instance:
.my-class{
color: map-get($red, 'lighten-5');
}
Edit: regarding the color function: The $primary-color: color("materialize-red", "lighten-2") line you posted is using a function defined in _color.scss, which ostensibly does the same thing as map-get but checks if the key exists in the map with map-has-key and raises a warning if it cannot be found.
#function color($color, $type) {
#if map-has-key($colors, $color) {
$curr_color: map-get($colors, $color);
#if map-has-key($curr_color, $type) {
#return map-get($curr_color, $type);
}
}
#warn "Unknown `#{name}` in $colors.";
#return null;
}
This syntax notation is called the SASS Maps notation and it is the SASS-equiv of a hash-map. Read more about it here.

Resources