Create multiple background using SASS mixin - css

I'm trying to create a mixin in Sass to generate multiple background, problem is the number of background is unknow, it's can be 3, 4 or even 5. Here what I try and fail.
#mixin multiBg($page: index, $sec: sec01,$from: 1, $to: 3, $type: jpg){
$url: (); // i'm try to create a empty array first
$newUrl: null; // and an empty variable
#for $i from $from through $to {
$newUrl: append($url, url(../img/#{$page}/#{$sec}_bg0#{$i}.#{$type})); // then append value to variable;
}
background: $newUrl;
}
#sec05 {
#include multiBg(index,sec05);
}
current output:
background: url(../img/index/sec05_bg03.jpg);
expected output:
background: url(../img/sec05_bg01.jpg),url(../img/sec05_bg02.jpg), url(../img/sec05_bg03.jpg);
I don't know how to fix this problem since i'm still learing SASS. Can someone enlighten me please.

You're on the right track! But your syntax and logic are slightly off. Here's what I came up with:
#mixin multiBg($page: index, $sec: sec01, $from: 1, $to: 5, $type: jpg) {
$url_list: ();
#for $i from $from through $to {
// I broke constructing the url and adding it to the set into two steps here.
// We could do this all at once, but separating it can make it easier to read.
// First, generate the url.
$url_string: url(../img/#{$page}/#{$sec}_bg0#{$i}.#{$type});
// Then add it to the list (the 'comma' part is important)
$url_list: append($url_list, $url_string, comma);
}
// Done looping? Output the final list!
background-image: $url_list;
}
That seems to return what you're looking for. Here are the official docs on list functions - I always forget one or two, may be useful for you too.
Also, since you mentioned you're new to sass - check out Sassmeister if you haven't already. It's a handy little sandbox for quickly prototyping and trying things out in sass; similar to Codepen but a bit more specialized. It's what I used to experiment with this question.

This is a cleaner answer, I believe.
#mixin image-resolve($image) {
$images: ();
#each $i in $image {
$path: ();
$images: append($images, $path, comma);
}
background-image: $images;
}

Related

Unable to use CSS Custom Properties (aka CSS Variables) with SASS #if Statement

I'm trying to pass some CSS Custom Properties to a SASS Mixin. I'm able use the variables when applied directly in the styling I want. But when I try to use a variable in an If statement, it doesn't work.
Mixin Example:
#mixin bg-color($hue, $status) {
background: hsl($hue, 50%, 50%); // $hue works as expected
#if $status == 'danger' { // doesn't work!
color: 'red';
} #else if $status == 'warning' { // doesn't work!
color: 'orange';
} #else { // always enters the else branch
color: 'black';
}
}
CSS:
:root {
--hue: 195;
--status: 'default';
}
.demo {
#include bg-color(var(---hue), var(---status));
}
If I manually add the status value to the mixin, it works:
.demo {
#include bg-color(var(---hue), 'danger');
}
Any idea what might be the issue?
UPDATE: As #temani-afif mentioned, this approach isn't possible because SASS files are compiled before CSS variables are used.
If you have some file, where you import all SCSS files, it depends which is imported first and which are imported after.
Make sure that one that you need to be Read by VS is first.
For example i needed to read first my variables, so it have to be first, other way, my code read mixin, and doesnt know yet what is '$blue'.

Get CSS Parameter from Typescript Angular

Is there a way to Get a variable that is set in the global scss file from a ts file in Angular (8)
I'm looking to use some of the defined variables dynamically in a canvas element defined in the ts code.
I have a way to do this using a styles service based on
https://en.programqa.com/question/52907585/
Within Global.SCSS
#mixin ExportVariables($map, $prefix: null) {
$mapPrefix: "--#{$prefix}";
#if ($prefix){
$mapPrefix: "#{$mapPrefix}-";
}
body {
#each $name, $value in $map {
#{$mapPrefix}#{$name}: $value;
}
}
}
--idle-state: #29ABE2;
// Import each of these in the theme service
$stateSCSS:(
idle: var(--idle-state),
);
#include ExportVariables($stateSCSS, 'stateSCSS');
In the Service
const bodyStyles = window.getComputedStyle(document.body);
this.stateSCSS = {
idle: bodyStyles.getPropertyValue('--stateSCSS-idle'),
};
I think this answers your questions: access SASS values ($colors from variables.scss) in Typescript (Angular2 ionic2)
TLDR:
Unfortunately, there is no way to access SASS variable directly from typescript/javascript code. However, we can make a workaround to access those variables.
You can view the workaround in the post mentioned above

Generating dynamic color map in SASS

I'm trying to generate a rather automated system to define colours in SASS. I have a list of colours, defined with a hexidecimal value (like so: $color--deep-ocean: #123143;) and a global $colors: (); definition.
I then want to create their RGBA values dynamically, and given variable interpolation isn't an option in SASS, I've tried my hands at maps.
The idea is to feed a set-color function a name and a color to populate my $colors variable with map-merge, which I can then retrieve with get-color. Here below are my two function definitions and how I'm trying to use them:
#function color-set($name, $hex) {
$submap: (hex: $hex);
#for $o from 0 to 20 { // Going in increments of 5
$percentage-decimal: $o*0.05;
$percentage: $o*5;
$submap: map-merge($submap, ($percentage: rgba($hex, $percentage-decimal)));
}
$colors: map-merge($colors, ($name: $submap));
/* We should then have a map that looks like this:
$colors: (colorname: (
hex: #000000,
0: rgba(0,0,0,0),
5: rgba(0,0,0,.05),
// and so on…
100: rgba(0,0,0,1)
)
)
… right? */
}
#function color-get($name, $opacity: hex) {
#if $opacity != hex { // Returns RGBA value
#return map-get(map-get($colors,$name), $opacity);
}
#else { // Returns hexidecimal value
#return map-get(map-get($colors,$name), hex);
}
}
Please let me know if my functions are confusing! I'll try to comment them better.
This is how I'm trying to define a colour (part of _variables.scss):
color-set(bkgrnd, $color--deep-ocean);
And here's how I'm trying to use my colours:
body { // These colours have been defined, too …supposedly
background-color: color-get(bkgrnd, 80);
color: color-get(white);
}
Here is the error I get on _variables.scss:
Invalid CSS after "...ackground color": expected 1 selector or at-rule, was "color-set(bkgrnd, $"
So I feel like I'm missing something. I've had my head wrapped around this for four hours and I'm going mad. It's probably super simple stuff but I can't seem to figure it out. I use SASS casually, so I might not be aware of some syntax issue but if anyone has a clue about how to fix this, I'd be quite grateful.
Have a nice day and thank you for taking the time to read my post!
Regards,
Chris
PS: I compile this in Brackets with the Brackets SASS plugin, if ever that information is relevant.
After digging some more, I found out what my issue was. SASS functions must have a #return directive in order to work. As a result, I updated my color-set function, and added #return $colors; at the end of it. Then, I just needed to give some directive so the function wouldn't be called "out of the blue", so I assigned my $colors variable to it like such:
$colors: color-set(bkgrnd, $color--deep-ocean);
I think it might be a bit repetitive to reassign $colors to itself all the time, but given this only affects performance during compilation, and not on my final CSS file, I can get away with it. There might be a better way (and I'm all ears if you have an idea!) but for now this fits my needs just fine.
And like that, I am able to handle my colors using maps. Thanks to anyone who had a look at my problem, and sorry for posting this - I should have taken some time to cool down and think some more. I hope this helps someone else who is stumbling on the same problem to fix their issues!
Take care,
Chris
PS: If ever you wanted it, below is the full code.
_colors.scss
$color--deep-ocean: #123143;
$color--yellow: #ffce00;
// And so on, and so forth…
_mixins.scss
#function color-set($name, $hexval) {
#return map-merge($colors, ($name: $hexval));
}
#function color-get($name, $opacity: hex) {
#if $opacity != hex { // Returns RGBA value
$opacity-decimal: $opacity/100;
#return rgba(map-get($colors,$name), $opacity-decimal);
}
#else { // Returns hexidecimal value
#return map-get($colors, $name);
}
}
_variables.scss
$colors: color-set(bkgrnd, $color--deep-ocean);
$colors: color-set(main, $color--yellow);
// And so on, and so forth again…
Usage example:
body {
background-color: color-get(bkgrnd); // Returns #123143
color: color-get(main); // Returns #ffce00
}
button {
border: 2px solid color-get(main, 50); // Returns rgba(255, 206, 0, 0.5)
}

SASS/SCSS's #if for choosing the type of image to use?

It's my first try using the #if control directive from SASS.
I have a list of optimized images in a folder. Some of them are smaller as JPGs and others are smaller as PNGs.
With the #if rule I'm trying to say "if a JPG of that file exists use this #include, else use the other one."
(The gif's in the example are there to clarify whether the "else if" part is right.)
My Example:
$list: A, B, C;
$type: jpg;
#mixin portfolio-images {
#each $item in $list {
a[href*="#{$item}"] span {
/* #if starts */
#if $type == jpg {#include background-image-retina("#{$item}.jpg");}
#else if $type == png {#include background-image-retina("#{$item}.png");}
#else {#include background-image-retina("#{$item}.gif");}
/* #if ends */
#include hide-text;
width: 300px;
height: 150px;
}
}
}
The JPGs display fine, but the PNGs don't display at all - no output is compiled in the CSS file.
I use the #include background-image-retina and can't define a custom variable for image type like in this fabulous mixin. So I'm not sure how to approach this.
Update: Like #lnrbob pointed out - it is not possible to check for existence of files with SASS. I marked his answer as correct since he provided an excellent #if example and in the long run helped me with this in understanding this SASS feature.
I'm confused what you are doing here. SASS won't check your file system to see if A.jpg or 'A.png` exists. You need to update the variable. So in your example (I think) it should look like this:
$list: A, B, C;
#mixin portfolio-images($type: 'jpg') {
#each $item in $list {
a[href*="#{$item}"] span {
/* #if starts */
#if $type == jpg {#include background-image-retina("#{$item}.jpg");}
#else if $type == png {#include background-image-retina("#{$item}.png");}
#else {#include background-image-retina("#{$item}.gif");}
/* #if ends */
#include hide-text;
width: 300px;
height: 150px;
}
}
}
And you'd use it like:
#include portfolio-images('png');
I don't think this is what you are wanting to achieve though is it? If you are wanting to replicate the functionality of the retina-compass helper (which you've linked to as #include background-image-retina) you need to do this as some ruby script to feed into the compiling process that SASS uses (in this example the helper uses Compass).
I hope this is, at least, mildly helpful. Please let me know if I've completely misunderstood and I'll review :)

Sass #each with multiple variables

I'm just getting started with Sass and Compass, and I'm loving it. Something I'd like to do is take advantage of the #each function to simplify repetitive tasks. However, I've only seen examples of #each inserting one variable, and I'd like to be able to use multiple variables.
The standard way (from the Sass Reference):
#each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
Which is great, but I'd like to be able to do something like:
#each {$animal $color} in {puma black}, {sea-slug green}, {egret brown}, {salamander red} {
.#{$animal}-icon {
background-color: #{$color};
}
}
Is this possible?
Just came across this, have the answer for you. In Sass, you can actually have a multidimensional list, so instead of constructing individual variables, you'd create one variable to hold them all, then loop over them:
$zoo: puma black, sea-slug green, egret brown, salamander red;
#each $animal in $zoo {
.#{nth($animal, 1)}-icon {
background-color: nth($animal, 2);
}
}
You can have multidimensional lists just like you would have single dimensional lists as long as each nested dimension is separated in a different manner (in our case, commas and spaces).
UPDATE Oct 24, 2013
In Sass 3.3, there is a new data type called maps which are a hashed set of items. With this, we can rewrite my previous answer in the following way to much more closely resemble the desired result:
$zoo: ("puma": black, "sea-slug": green, "egret": brown, "salamander": red);
#each $animal, $color in $zoo {
.#{$animal}-icon {
background-color: $color;
}
}
You can see this in action over at SassMeister
I'm in the same boat (beginner to Sass/Compass) and had to do something similar. Here's what I came up with, using nested lists:
$flash_types: (success #d4ffd4) (error #ffd5d1);
#each $flash_def in $flash_types {
$type: nth($flash_def, 1);
$colour: nth($flash_def, 2);
&.#{$type} {
background-color: $colour;
background-image: url(../images/#{$type}.png);
}
}
It's not the most elegant solution but it should work if you can't find anything else. Hope it helps! I'd appreciate a better method too :)
Another way I used if anyone needs it:
$i:0;
#each $name in facebook, twitter, google_plus, instagram, youtube, pinterest {
$i:$i+1;
}
This functionality is supported for Sass 3.3.0 and above (I just updated from 3.2.14 to 3.4.4 in order to use it).
#each $animal, $color in (puma, black), (sea-slug, green), (egret, brown), (salamander, red) {
.#{$animal}-icon {
background-color: $color;
}
}
I'd recommend to check the changelog for backwards incompatibilities, if you're updating Sass.
Sass reference for multiple assignments with #each
Another solution could be to create different lists and "zip" them.
//Create lists
$animals: puma, sea-slug, egret, salamander;
$animals-color: black, green, brown, red;
//Zip lists
$zoo: zip($animals, $animals-color);
//Do cycle
#each $animal, $color in $zoo {
.#{$animal}-icon {
background-color: $color;
}
}
Probably this solution is more complicated to mantain than the others, but if you use a list more than one time, you can save time. (was my case)

Resources