Why doesn't SASS resolve the calculation? - sass

Why doesn't SASS resolve the calculation?
$animation-speed-half-life: 1s;
#for $i from 0 through 31 {
&:nth-child(#{$i}) {
transition-delay: #{$animation-speed-half-life - $animation-speed-half-life / $i};
}
}
Instead it outputs transition-delay: 1s - 1s/1;

I'm not sure why Sass won't calculate that but you don't actually need to interpolate the value of transition-delay, as there's no CSS going on around it.
This would be my implementation of your code:
#mixin incremental-transition-delay($child-count, $half-life: 1s) {
#for $i from 1 through $child-count {
&:nth-child(#{$i}) {
transition-delay: $half-life - $half-life / $i;
}
}
}
.thing {
#include incremental-transition-delay(32, 1s);
}

Did you already debug it?
I tested your code at Sassmeister (SASS v3.4.21), and it shows me a reference error:
Base-level rules cannot contain the parent-selector-referencing
character '&'.
DEBUG
$animation-speed-half-life: 1s;
$i: 1;
$test: #{$animation-speed-half-life - $animation-speed-half-life / $i};
#error $test; // this will render '0s' as expected
.parentElement { // comment this to show the reference error
#for $i from 0 through 31 {
&:nth-child(#{$i}) {
transition-delay: #{$animation-speed-half-life - $animation-speed-half-life / $i};
}
}
}
Sassmeister Fiddle
Not sure, if that's your complete code or just a snippet but it warns me the error I quoted above. It looks for a parent element which doesn't exist. Probably, that's why in your version it won't calculate. The .parentElement is just a dummy to provide you the working way.
POSSIBLE FIX
Add a #if-condition that checks if a parent element exists:
#if & { ... }
So basically wrap the condition around the loop:
#if & {
#for $i from 0 through 31 {
&:nth-child(#{$i}) {
transition-delay: #{$animation-speed-half-life - $animation-speed-half-life / $i};
}
}
}
Sassmeister Fiddle
The if & { .. statement is optional. Just wanted to show you how to bug out the error. I am not sure if your SASS version still interpolates the calculation during an error or not.
My own personal way would be using a placeholder without the if & statement because a placeholder functions as a parent element and no error will occur. Even if the element doesn't exist but that's what placeholders are for:
%test {
#for $i from 0 through 31 {
&:nth-child(#{$i}) {
transition-delay: #{$animation-speed-half-life - $animation-speed-half-life / $i};
}
}
}
parent {
#extend %test;
}
Sassmeister Fiddle
A Mixin would work also but your loop doesn't need any parameter to function so a placeholder should do it.

Related

How to increment up between 0 and 1 with scss

In regards to SCSS, the following generates 2 classes for me between 0 and 1
#for $i from 0 through 1 {
.op-#{1 * $i} {
opacity: #{1 * $i};
}
}
which results in
.op-0 {
opacity: 0;
}
.op-1 {
opacity: 0.1;
}
but how can I get
.op-0 {
opacity:0;
}
.op-01 {
opacity:0.1;
}
.op-02 {
opacity:0.2;
}
//...etc...
.op-1 {
opacity:1.0;
}
I tried the following...
#for $i from 0 through 1 {
.op-#{0.10 * $i} { //I know this part is wrong - not sure how to do this correctly...
opacity: #{.10 * $i};
}
}
but it throws an error. Thanks for any tips!
If you do not want specific classname requirements then you can try below solutions, it will be just that your compiled css classnames will starts from .opacity1 to .opacity2.
All you need is loop thought 10 times.
#for $i from 1 through 10 { //means start from i=1 to till i=10, generate below css
.op-#{1 * $i} {
opacity: #{$i/10};
}
}
In sass for loop valid number after from is starting value of loop and whatever valid number we write after through is ending point.
#for $i from 1 through 10, this statement means start from 1 till 10.
opacity: #{$i/10};, just logic for generating expected opacity value.

scss providing css classes with . inside

I have a for loop in scss and I would like to output something like this:
.font-1.0em {font-size:1.0em}
.font-1.1em {font-size:1.1em}
.font-1.2em {font-size:1.2em} ....
I wrote the scss as this
#for $i from 1 through 50 {
$val: $i + em;
$val2: $i / 10 + em;
&.font-#{$val} {
font-size: #{$val2} ;
}
}
which outputs
.font-10em {font-size:1.0em}
.font-11em {font-size:1.1em}
.font-12em {font-size:1.2em} ....
Is there anyway to fix this?
The thing you are trying to achive should be fairly easily solved, by using, same formula you have in $val2 in your $val
#for $i from 1 through 50 {
$val: $i / 10 + em;
$val2: $i / 10 + em;
&.font-#{$val} {
font-size: #{$val2} ;
}
}
compiles to
.font-0.1em {
font-size: 0.1em;
}
.font-0.2em {
font-size: 0.2em;
}
Or am I missing something?

sass #for within #each, where #for is using key, value pair of #each

I was not able to find the answer to my question: WTF - why?!
Variables
$breakpointNames: (xs, sm, md, lg, xl);
$breakpointSizes: (480px, 667px, 845px, 1024px, 1280px);
$breakpoints: createMapOutOfLists($breakpointNames, $breakpointSizes);
$masonryLayoutColumnsCount: (2, 2, 3, 4, 4);
$masonryLayoutColumns: createMapOutOfLists($breakpointNames,
$masonryLayoutColumnsCount);
Mixin
#mixin media($min, $max: false) {
#if $max == false {
#if $min == xs {
#media (min-width: 0px) {
#content;
}
}
#media (min-width: #{map-get($breakpoints,$min)}) {
#content;
}
} #else if $min == 0 {
#media (max-width: (#{map-get($breakpoints,$max)} - 1)) {
#content;
}
} #else {
#media (min-width: #{map-get($breakpoints,$min)}) and (max-width: (#{map-get($breakpoints,$max)} - 1)) {
#content;
}
}
}
I wrote this:
#each $breakpoint, $column-count in $masonryLayoutColumns {
#include media($breakpoint) {
.masonry-tile {
width: 100% / $column-count;
}
}
#for $i from 1 through $column-count {
#include media($breakpoint) {
.masonry-tile:nth-child(#{$i}) {
-webkit-order: $i;
order: $i;
}
}
}
}
That threw following Error:
Error in plugin 'sass'
Message:
../../../app/Resources/assets/sass/functions/_map_generators.scss
Error: 2 is not an integer.
on line 4 of
../../../app/Resources/assets/sass/functions/_map_generators.scss
>> merge($map, (#{nth($listOfKeys, $index)}: #{nth($listOfValues, $index)}));
------------------------------------------^
That the error is at a wrong place or maybe entirely wrong, is another issue and currently irrelevant - to me - right now.
After some time of searching without results and trying to fix it on my own, I got it to work with the following:
#for $index from 1 through length($masonryLayoutColumns) {
$breakpoint: nth($breakpointSizes, $index);
$column-count: nth($masonryLayoutColumnsCount, $index);
#include media($breakpoint) {
.masonry-tile {
width: 100% / $column-count;
}
}
#for $i from 1 through $column-count {
#include media($breakpoint) {
.masonry-tile:nth-child(#{$i}) {
-webkit-order: $i;
order: $i;
}
}
}
}
Okay, that works, but I don't like it.
I prefer the first version.
Is there a good reason why the first version is not working? Or is it a bug?
Thanks in advance!
The only reason your code didn't work is because you must be passing a string in the map that you are creating.
$column-count should be an integer, in order to do your width manipulation (width: 100% / $column-count;)
I have attached a sample pen, with integer data, which will resolve your issue.
$masonryLayoutColumns: (
'760px': 8,
'990px': 12,
'1024px': 16
);
#each $breakpoint, $column-count in $masonryLayoutColumns {
#media(min-width: $breakpoint) {
.masonry-tile {
width: 100% / $column-count;
}
}
#for $i from 1 through $column-count {
#media(min-width: $breakpoint) {
.masonry-tile:nth-child(#{$i}) {
-webkit-order: $i;
order: $i;
}
}
}
}
https://codepen.io/anon/pen/LLBPaP
Note: I don't have your mixin's so I am just writing a generic media query.

SASS & list iteration / delimiter

I've got a pattern where I create a list of lists to iterate over, as an basic example:
$carouselContent : "carousel-content-1" "buying_carousel_image_1.jpg",
"carousel-content-2" "buying_carousel_image_2.jpg";
My iteration (inside of a mixin) then looks like:
#each $carousel in $carouselContent {
$baseClass: nth($carousel, 1);
$image: nth($carousel, 2);
.#{$baseClass} {
....
}
}
I just came across a page that presently only has 1 item in the carousel. I'd like to keep with the pattern, but I'm not sure how to do so. If I iterate over:
$carouselContent : "carousel-content-1" "growing_carousel_image_1.jpg";
SASS treats that as a 2 item list. I could work around that by adding an empty item to my list, then adding a check against empty string, e.g.
$carouselContent : "carousel-content-1" "growing_carousel_image_1.jpg","" "";
But that seems hacky... so I figured there has to be a way to do this that I'm unaware of.
In Sass 3.3.0, all you need to do is have a trailing comma to signify that what you have is a list with one item in it:
$carouselContent : "carousel-content-1" "buying_carousel_image_1.jpg", ;
#each $carousel in $carouselContent {
$baseClass: nth($carousel, 1);
$image: nth($carousel, 2);
.#{$baseClass} {
color: red;
}
}
Generates:
.carousel-content-1 {
color: red;
}
Sass 3.3.0 is still undergoing development, but you can play with it now by upgrading to the latest edge version via gem install sass --pre. However, if you're willing to upgrade to 3.3, you may want to look at mappings instead (see: the change log)
You can use an #if directive to check if the first element of your list is also a list with type-of() (and only then use the loop). Something along these lines (I separated the block from inside your loop as a mixin):
#mixin do_car($carousel) {
$baseClass: nth($carousel, 1);
$image: nth($carousel, 2);
.#{$baseClass} {
/* ... */
}
}
#if (type-of(nth($carouselContent,1)) == list) {
#each $carousel in $carouselContent {
#include do_car($carousel);
}
} #else {
#include do_car($carouselContent);
}
DEMO
If your items are numbered sequentially, you can use a for loop instead:
$carouselImages: 2;
#for $i from 1 through $carouselImages {
.#{carousel-content-#{$i}} {
background: url(buying_carousel_image_#{$i}.jpg);
}
}
Output:
.carousel-content-1 {
background: url(buying_carousel_image_1.jpg);
}
.carousel-content-2 {
background: url(buying_carousel_image_2.jpg);
}
Alternately:
//$carouselContent : "buying_carousel_image_1.jpg", "buying_carousel_image_2.jpg";
$carouselContent : "buying_carousel_image_1.jpg";
#for $i from 1 through length($carouselContent) {
.#{carousel-content-#{$i}} {
background: url(nth($carouselContent, $i));
}
}

How do I combine a range of sass classes that are created in a loop

I am using SASS to construct a range of classes from variables passed into a mixin.
#mixin classes($key, $num) {
#for $i from 1 through $num {
[class*=#{$key}-#{$i}] {
#content
}
}
}
#include classes(grid, 8) {
width:100px;
}
It currently makes the classes like I want, but all as 8 separate classes (which are identical in #contents. Is there a way to merge them all together so I get:
[class*=grid-1],
[class*=grid-2],
....
[class*=grid-8],
{
width:100px;
}
I'm not sure if it's even possible to do this? Any pointers would be greatly appreciated.
Thanks,
Carl
I found the answer eventually
$classes: ();
#for $i from 1 through $cols {
$classes: join($classes, unquote("#{$prefix}#{$i} "), comma);
}
#{$classes} {
float: left;
margin-right: $gutterPercent;
width: $columnWidth;
}

Resources