Can you have an array inside a sass object value? - css

I'm trying to have an array inside an object's value.
$background-things: (
'a': ['100vh', 'transparent', 'column'],
'higher': ['70vh', '#000', 'column'],
'lower': ['30vh', '#fff', 'row'],
);
and then later call them like this:
#each $name, $value in $background-things {
#background {
&-#{$name}: {
#include column($height:$value[0], $background-color:$value[1], $flex-direction:$value[2]);
}
}
}
This doesn't work. Is there any way to do this? On a side note, does the value $name work, because in the object's property I put '&-a'.

It is possible. #each part needs some modification:
&-#{$name}: should convert to &-#{$name}.
Access to list (array) items is possible with nth function; for example nth($value, 1).
lists indexes start from 1.
Also '100vh' doesn't need '.
More information about lists: https://sass-lang.com/documentation/modules/list
#each $name, $value in $background-things {
#background {
&-#{$name} {
#include column($height:nth($value, 1), $background-color:nth($value, 2), $flex-direction:nth($value, 3));
}
}
}

Related

SASS string to "non string"

I have a scenario where I am using a JSON file in order to dynamically create SASS variables. The plugin (Gulp-json-css) can retain the map and array properties, but does not add quotations onto the map keys:
$palettes : ( white: #ffffff, grey: (lite: #aaaaaa, base: #999999, dark: #666666), black: #000000);
I am running into an issue where map-get() is not able to find the appropriate value if a quoted string is used for the parameter.
map-get($palettes, white) => #ffffff
map-get($palettes, "white") => null
--
Conclusion : (white != "white")
Is there anyway to change a quoted string into an "unquoted" string? I know what you're thinking, but unquote() doesn't work either:
$color : "white";
white == unquote($color) => false
I need a way to turn "white" into white in order to appropriately retrieve the correct value using the map-get() function.
UPDATE / SOLUTION
To whoever comes across this page and is looking for a solution, I ended up writing a function that will loop through a map and add quotes to it's keys:
#function quoteMapKeys( $map )
{
$newMap : ();
#each $key,$value in $map
{
#if type-of($value) == 'map'
{
$value : quoteMapKeys( $value );
}
$newMap : map-merge($newMap, (quote($key):$value));
}
#return $newMap;
}
$palettes : quoteMapKeys( $palettes );

Check if SASS function argument is a list with one or more items

I need to build a function where the argument passed to the function is a variable list which in some cases may contain only one item, like following:
$example-list-1: grey 20; // this is a single list item
$example-list-2: grey 20, grey 30; // this is a list with two items separated by comma
#function box-shadow($params-list) {
// ...
// here comes the problem
#each $item in $params-list {
// if $example-list-1 is passed as argument it will be considered a list with two items!
}
}
In order to avoid that problem I need to perform a check to see what kind of list was passed as argument, and in case of a list with one item I have to fake it like having multiple items, like this:
#function box-shadow($params-list) {
#if (params-list has only one item) {
$params-list: append($params-list, null, comma);
}
// problem solved
#each $item in $params-list {
// perform the magic
}
#return $result;
}
So, the question is how to check if params-list has only one item? Or, is there any workaround to solve this problem?
EDIT:
I found sort of a viable hack, to add an empty list item separated by comma, like this:
$example-list-1: grey 20, ();
The thing is that I can use this hack just by manually edit the variables, but not programatically! So the question remains...
I found a function inside the docs, it can be used to perform the check if separator is comma, and if not the list is rebuilded as a comma separated list:
#use "sass:list";
//...
#function box-shadow($params-list) {
// check if separator is comma, if not rebuild the list
#if list.separator($params-list) != comma {
$new-list: ();
$params-list: append($new-list, $params-list, comma);
#debug list.separator($params-list);
}
// loop now works as expected
#each $item in $params-list {
// code
}
}
EDIT:
I also wrote two helper functions, can be used when a list is expected in some format:
// convert to comma separated list
#function comma-separated-list($list) {
#if list.separator($list) != comma {
$new-list: ();
$list: append($new-list, $list, comma);
// #debug list.separator($list);
}
#return $list;
}
// convert to space separated list
#function space-separated-list($list) {
#if list.separator($list) != space {
$new-list: ();
$list: append($new-list, $list, space);
// #debug list.separator($list);
}
#return $list;
}

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

SASS can I compose a variable name with a string and list value

I have a number of SASS variables that reference SVG icons. Below is a simplified example:
I would like to be able to loop through a list of strings and compose the SASS variable name in a way that's presented using the background style of the icon-checkbox class. My approach so far does not work. Can I anyone show me how/if this can be done in SASS.
$icon-trash-grey: "data:image/svg+xml;charset=UTF-8,<svg data>";
$icon-save-grey: "data:image/svg+xml;charset=UTF-8,<svg data>";
$icon-list: trash, save; // list of icon names
.icon-checkbox {
each $key in $icon-list {
background: url($icon-#{$key}-grey);
// other styles
}
}
Thanks in advance
The following SASS
$icon-trash-grey: "data:image/svg+xml;charset=UTF-8,<svg data>";
$icon-save-grey: "data:image/svg+xml;charset=UTF-8,<svg data>";
$icon-map: (
trash: $icon-trash-grey,
save: $icon-save-grey,
);
.icon{
#each $key, $value in $icon-map {
&.#{$key} {
background: url($value);
}
}
}
renders this CSS
.icon.trash {
background: url("data:image/svg+xml;charset=UTF-8,<svg data>");
}
.icon.save {
background: url("data:image/svg+xml;charset=UTF-8,<svg data>");
}
You can have a look, make edits or fork this Sassmeister
Try this :
$icon-list : (
"icon-trash-grey": "data:image/svg+xml;charset=UTF-8,<svg data>",
"icon-save-grey": "data:image/svg+xml;charset=UTF-8,<svg data>"
);
#each $key, $val in $icon-list {
.#{$key} {
background: url($val);
}
}

Get variable name from variable value in SASS/SCSS

I'd like to access variable within an #each loop using defined value like in the following example:
$car:true;
$people:false;
$job:false;
#mixin options($someval){
#each $prefix in car,people,job{
#if $#{$prefix} == true{
//some CSS...
}
}
}
Variable would be a sort of "semaphores" that define whether print or not Css rules.
My big doubt is how can I check over dynamically defined variables name ?
I've tried with $#{$prefix} but it doesn't work.
EDIT ---------------------------
I'd like to obtain this CSS
car-something: 34px;
Where the word "car" is taken from $prefix and in the first round of #each loop $#{$prefix} becomes $car
The problem is on $#{$prefix} ... it doesn't work :P i get an error
This is an old question but since it has no valid answer, here it is
You need to pass a map to #each
$car:true;
$people:false;
$job:false;
#mixin options($someval){
#each $key, $val in (car: $car, people: $people, job: $job) {
#if $val == true{
#{$key}-something: $someval
}
}
}
test {
#include options(34px)
}
Instead of trying to interpolate a variable name, pass a list to the mixin.
$car: true;
$people: false;
$job: false;
$thing-list: $car, $people, $job;
#mixin thingamajig($thing-list) {
#each $thing in $thing-list {
#if $thing {
// Some CSS
}
}
}

Resources