Converting LESS "when" statements into SCSS conditional statements - sass

To cite my sources, I'm converting the tiles functionality from Metro-UI into a custom SCSS/Angular project I'm building. So far I've been able to convert much of it 1:1 by watching for mixins, includes, and variables. However, I'm not following what Metro's team is doing in this section when it comes to column arrangement. Their original code (from their LESS file - line 243):
.tiles-grid {
.create-tiles-cells(#i: 1, #k: 1) when (#k <= #i) {
.tile-small.col-#{k} {
grid-column: #k / span 1;
}
.tile-medium.col-#{k} {
grid-column: #k / span 2;
}
.tile-wide.col-#{k} {
grid-column: #k / span 4;
}
.tile-large.col-#{k} {
grid-column: #k / span 4;
}
.tile-small.row-#{k} {
grid-row: #k / span 1;
}
.tile-medium.row-#{k} {
grid-row: #k / span 2;
}
.tile-wide.row-#{k} {
grid-row: #k / span 4;
}
.tile-large.row-#{k} {
grid-row: #k / span 4;
}
//.col-#{k} {
// grid-column: #k;
//}
//.row-#{k} {
// grid-row: #k;
//}
.create-tiles-cells(#i; #k + 1);
}
.create-tiles-cells(12);
}
.tiles-grid {
&.size-half {
width: 70px + #tileMargin * 2;
}
.create-tiles-grid-size(#i: 1, #k: 1) when (#k <= #i) {
&.size-#{k} {
width: (#tileCellSize + #tileMargin * 2) * #k;
}
.create-tiles-grid-size(#i; #k + 1);
}
.create-tiles-grid-size(10);
}
.tiles-grid {
.generate-tiles-media-options(#mediaBreakpointListMobileLength);
.generate-tiles-media-options(#name, #j: 1) when (#j <= #mediaBreakpointListMobileLength) {
#m: extract(#mediaBreakpointListMobile, #j);
#media screen and (min-width: ##m) {
.create-tiles-cells(#i: 1, #k: 1) when (#k <= #i) {
.col-#{m}-#{k} {
grid-column: #k;
}
.row-#{m}-#{k} {
grid-row: #k;
}
.create-tiles-cells(#i; #k + 1);
}
.create-tiles-cells(12);
.create-tiles-grid-size(#i: 1, #k: 1) when (#k <= #i) {
&.size-#{m}-half {
width: 70px + #tileMargin * 2;
}
&.size-#{m}-#{k} {
width: (#tileCellSize + #tileMargin * 2) * #k;
}
.create-tiles-grid-size(#i; #k + 1);
}
.create-tiles-grid-size(10);
}
.generate-tiles-media-options(#name, #j + 1);
}
}
My conversion so far:
.tiles-grid {
#mixin create-tiles-cells($i: 1, $k: 1) when ($k <= $i){
.tile-small.col-#{$k} {
grid-column: $k / span 1;
}
.tile-medium.col-#{$k} {
grid-column: $k / span 2;
}
.tile-wide.col-#{$k} {
grid-column: $k / span 4;
}
.tile-large.col-#{$k} {
grid-column: $k / span 4;
}
.tile-small.row-#{$k} {
grid-row: $k / span 1;
}
.tile-medium.row-#{$k} {
grid-row: $k / span 2;
}
.tile-wide.row-#{$k} {
grid-row: $k / span 4;
}
.tile-large.row-#{$k} {
grid-row: $k / span 4;
}
//.col-${k} {
// grid-column: $k;
//}
//.row-${k} {
// grid-row: $k;
//}
#include create-tiles-cells($i, $k + 1);
}
#include create-tiles-cells(12);
}
.tiles-grid {
&.size-half {
width: 70px + $tileMargin * 2;
}
#mixin create-tiles-grid-size($i: 1, $k: 1) when ($k <= $i){
&.size-#{$k} {
width: ($tileCellSize + $tileMargin * 2) * $k;
}
#include create-tiles-grid-size($i, $k + 1);
}
#include create-tiles-grid-size(10);
}
.tiles-grid {
#include generate-tiles-media-options($mediaBreakpointListMobileLength);
#mixin generate-tiles-media-options($name, $j: 1) when ($j <= $mediaBreakpointListMobileLength){
$m: extract($mediaBreakpointListMobile, $j);
#media screen and (min-width: $m) {
#mixin create-tiles-cells($i: 1, $k: 1) when ($k <= $i){
.col-#{$m}-#{$k} {
grid-column: $k;
}
.row-#{$m}-#{$k} {
grid-row: $k;
}
#include create-tiles-cells($i, $k + 1);
}
#include create-tiles-cells(12);
#mixin create-tiles-grid-size($i: 1, $k: 1) when ($k <= $i){
&.size-#{$m}-half {
width: 70px + $tileMargin * 2;
}
&.size-#{$m}-#{$k} {
width: ($tileCellSize + $tileMargin * 2) * $k;
}
#include create-tiles-grid-size($i, $k + 1);
}
#include create-tiles-grid-size(10);
}
#include generate-tiles-media-options($name, $j + 1);
}
}
It's of course the "when" statement that is causing the issue. I understand from similar questions that I may need to use a "for" or "each" statement and break it down from there, but the syntax rules are very different logic when I'm reviewing similar answers (like this one). Since I didn't author the original LESS syntax I'm trying to work backwards through their logic to determine its SCSS equivalent.
From what I can tell it's trying to determine how to spread out the grids if/when the two values for I and K are different, but since you can't create a new class based upon a conditional variable in SCSS I'm getting tripped up. I'd appreciate any guidance. This is the last portion of my code that won't compile.

LESS and SCSS are a bit different when it comes to syntax – I always found SCSS to be the better choice – why my knowledge on LESS is somewhat limited.
I ran the LESS code on codepen and looked at the output – I think I'm able to help you with the first two parts. The last part with the media queries makes no sense it just produces a bunch of media queries and classes doing the same thing as the size part...
(let me know if you can produce something meaningful - then I'll have a second look).
I hope the comments makes sense :-)
Code on sassmeister.com
// -------------------------------------------------------
// Create tile cells mixin
// if no arguments are passed 12 will be used as default
// small note! mixins can't be nested in selectors
// -------------------------------------------------------
#mixin create-tiles-cells($count: 12){
// map holding size information (think object like)
$sizes:(small: 1, medium: 2, wide: 3, large: 4);
// outer selector
.tiles-grid {
// loop from 1 through cell count
#for $i from 1 through $count {
// loop through sizes map
#each $key, $value in $sizes {
// print class using $key (small, medium,...)
.tile-#{$key} {
// use & to bind the .col and .row class to the parent .tile-xxx
&.col-#{$i} { grid-column: $i / span $value; }
&.row-#{$i} { grid-row: $i / span $value; }
}
}
}
}
}
// -------------------------------------------------------
// Create tile sizes mixin
// if no arguments are passed 10 will be used as default
// -------------------------------------------------------
#mixin create-tiles-grid-size($count: 10){
// variables
$tile-margin: 5px;
$tile-cell-size: 150px;
// #tileMargin: 5px;
.tiles-grid {
// hardcoded half class
&.size-half { width: 70px + $tile-margin * 2;}
// loop from 1 through size count
#for $i from 1 through $count {
&.size-#{$i}{
width: ($tile-cell-size + $tile-margin * 2) * $i;
}
}
}
}
// -------------------------------------------------------
// Include the mixins
// -------------------------------------------------------
#include create-tiles-cells(12);
#include create-tiles-grid-size(10);

Related

unable to pass value to the sass mixin variable

I am trying to write a mixin that will take the HEX color code and convert it to HSL. Every time the code is compiled it gives an error. tried to use #return to pass the variable but that also not working. help me fix the code.
Thanks in advance.
Error:
Compilation Error
Error: Undefined variable.
╷
43 │ $hue : $hue * 60;
│ ^^^^
╵
code inside _mixin.scss:
#mixin hex-to-hsl($hex) {
$red: red($hex);
$green: green($hex);
$blue: blue($hex);
$max: max($red, $green, $blue);
$min: min($red, $green, $blue);
$delta: calc($max - $min);
$lightness: calc(($max + $min) / 2);
#if ($delta == 0) {
$hue: 0;
$saturation: 0;
} #else {
#if ($lightness < 0.5) {
$saturation : calc($delta / ($max + $min));
} #else {
$saturation : calc($delta / (2 - $max - $min));
}
#if ($red == $max) {
$hue : calc(($green - $blue) / $delta);
} #else if ($green == $max) {
$hue : calc(2 + ($blue - $red) / $delta);
} #else {
$hue : calc(4 + ($red - $green) / $delta);
}
$hue : $hue * 60;
#if ($hue < 0) {
$hue : calc($hue + 360);
}
}
color: hsl($hue, $saturation * 100%, $lightness * 100%);
}
code in main.scss
$main-color: #4F6D7A;
.text3 {
#include hex-to-hsl($main-color);
}

Processing 3.3.7 draw() stops looping

I wrote this code on Processing 3.3.7, it creates a ball that bounces around.
Ball b;
int n = 0;
void setup() {
size(600, 400);
b = new BallBuilder()
.buildRadius(20)
.buildXSpeed(5)
.buildYSpeed(5)
.buildYAcceleration(1)
.toBall();
}
void draw() {
background(0);
n++;
print("n: " + n + " | ");
print("xSpeed: " + b.getXSpeed() + " | ");
println("ySpeed: " + b.getYSpeed());
b.display();
b.move();
}
There is also a Ball class, which has these methods:
void display() {
fill(255);
stroke(255);
ellipse(xPosition, yPosition, radius * 2, radius * 2);
}
void move() {
this.moveX();
this.moveY();
}
private void moveX() {
for(float i = 0; i <= abs(this.xSpeed); i += abs(this.xSpeed) / 10) {
this.bounceX();
this.xPosition += this.xSpeed / 10;
}
}
private void moveY() {
for(float i = 0; i <= abs(this.ySpeed); i += abs(this.ySpeed) / 10) {
this.bounceY();
this.yPosition += this.ySpeed / 10;
}
this.ySpeed += this.yAcceleration;
}
void bounceX() {
if(!this.canMoveX()) {
this.xSpeed = -this.xSpeed;
}
}
void bounceY() {
if(!this.canMoveY()) {
this.ySpeed = -this.ySpeed;
}
}
boolean canMoveX() {
if(this.xPosition < radius || this.xPosition >= width - this.radius) {
return false;
}
return true;
}
boolean canMoveY() {
if(this.yPosition < radius || this.yPosition >= height - this.radius) {
return false;
}
return true;
}
}
And there's also a builder and two getters for the Ball(not posted here, as they're pretty straight forward). The problem is, neither the xSpeed nor the ySpeed can be set to 0, otherwise the code stops running. That means that I need to give it both speeds when instantiating and if I set the acceleration makes the speed go to 0, the program stops running (the n variable is used to count the number of times the draw() loops, when the speed hits 0, it stops increasing). What am I missing?
Have you tried debugging your code to figure out where the code differs from what you expected?
You have two loops like this:
for(float i = 0; i <= abs(this.xSpeed); i += abs(this.xSpeed) / 10) {
You might add a print statement inside these loops, like this:
println("i: " + i);
If you did this, you'd discover that i is always 0. Why is that?
Think about what happens if this.xSpeed is 0: when will this loop exit?

Rewrite SASS function to LESS

How could you convert this function written in SASS to LESS? It converts pixelvalues to rem.
#function unit($number) {
#return $number / ($number * 0 + 1);
}
#function getRems($Pixels, $_base-fontsize:16px) {
$getRems: ();
#each $pixel in $Pixels {
$getRems: append($getRems, strip-unit($pixel) / strip-unit($_base-
fontsize) + rem,'space');
}
#return $getRems;
}
.image {
padding:getRems(250px 25px 10px 50px);
}

SCSS/SASS list reverse iteration (backward loop)

Reversing the order of a #for iteration output in SCSS can be done as so:
SCSS example: GIST DEMO
$colors : green, gold, red;
a{
$i : length($colors);
#each $c in $colors {
&:nth-child(#{$i}){
fill:$c;
}
$i : $i - 1;
}
}
Output:
a:nth-child(3) {
fill: green;
}
a:nth-child(2) {
fill: gold;
}
a:nth-child(1) {
fill: red;
}
Is this the best way of SASS reverse iterating?
Does anyone know of a more "SCSS native" way of achieving this goal which increases readability?
Your solution is ok.
You can create a function that will reverse your array:
#function reverse($list, $recursive: false) {
$result: ();
#for $i from length($list)*-1 through -1 {
#if type-of(nth($list, abs($i))) == list and $recursive {
$result: append($result, reverse(nth($list, abs($i)), $recursive));
}
#else {
$result: append($result, nth($list, abs($i)));
}
}
#return $result;
}
$list: #aaa, #bbb, #ccc, #ddd;
$new-list: reverse($list);
#for $i from 1 through length($new-list){
div:nth-child(#{$i}){
color: nth($new-list, $i);
}
}
You can use nth-last-child selector.
#for $i from 1 through length($list){
div:nth-last-child(#{$i}){
color: nth($list, $i);
}
}
You can rewrite your array: $list: #ddd, #aaa, #bbb, #ccc and use nth-child.

Sass passing quoted math string into mixin

So I'm trying to pass a modifier into a SASS mixin:
$headerHeight: 40px;
#mixin hh($prop, $mod: " + 0") {
#{$prop}: #{$headerHeight + $mod};
}
.something {
#include hh(padding-top, " * 2"); // Should return padding-top: 80px;
}
I keep getting things like padding-top: 40px + 0; no matter how many times I try and unquote it. Is it not possible to have the math string evaluated inside a mixin?
I've tried it without the px on $headerHeight, but that doesn't seem to work either.
I can do something like this:
#mixin hh($prop, $aMod: 0px, $mMod: 1) {
#{$prop}: ($headerHeight + $aMod) * $mMod;
}
But I'd prefer to just be able to put any arbitrary math string in there instead of having to break up the additive and multiplicative aspects of the math.
Thanks
Unfortunately, you would have to do something like create functions that act as operators for you and call them with the call() function inside your mixin:
#function plus($i, $j: 0) {
#return $i + $j;
}
#function times($i, $j: 0) {
#return $i * $j;
}
$headerHeight: 40px;
#mixin hh($prop, $func, $mod) {
#{$prop}: call($func, $headerHeight, $mod);
}
.something {
#include hh(padding-top, 'plus', 2); // 42px
#include hh(padding-bottom, 'times', 2); // 80px
}
I don't think that this is possible, you could do something like the following however to achieve the same goal:
$headerHeight: 40;
#mixin hh($prop, $mod, $modval) {
#if $mod == '+' {
#{$prop}: $headerHeight + $modval * 1px;
}
#if $mod == '-' {
#{$prop}: $headerHeight - $modval * 1px;
}
#if $mod == '*' {
#{$prop}: $headerHeight * $modval * 1px;
}
#if $mod == '/' {
#{$prop}: $headerHeight / $modval * 1px;
}
}
.something {
#include hh(padding-top, '*', 2); // Should return padding-top: 80px;
}
http://sassmeister.com/gist/be55fe73c307d0ad018c

Resources