Harry L Harry L - 20 days ago 5
Sass (Sass) Question

Creating values in SASS map for modular scale ms-range

What I am trying to do is


  • loop through a map $breakpoints,

  • pull out the min value for each breakpoint,

  • calculate an em value based on each,

  • then use these for a global map $ms-range



This code needs to product a variable that looks like this:

$ms-range:
1.2 20em,
1.333 30em,
1.618 40em,
1.8 50em,
2 60em;


I can't get the function to return the format I want. Perhaps a map-extend?! I don't know. I need a SASS master!

SASS:

$breakpoints: ( s: (320, 479), sm: (480, 767), m: (768, 1023), l: (1024, 1439), xl: (1440, null));


@function returnThatMap() {
@each $name, $values in $breakpoints {
@for $i from 1 through length($name) {
$min: nth($values, 1);
// if the last one
@if ($i == length($name)) {
@return 'calc($i * 1.2) $min / 16 * 1em'
}
// if not the last one
@else {
@return 'calc($i * 1.2) $min / 16 * 1em',
}
}
}
}

$ms-range : returnThatMap() ;


// OUTPUT FORMAT NEEDED below!! (dummy numbers, but correct syntax - ie. number ' ' [number]em,number ' ' [number]em, number ' ' [number]em;)

// $ms-range:
// 1.2 20em,
// 1.333 30em,
// 1.618 40em,
// 1.8 50em,
// 2 60em;


SASSMEISTER LINK:
http://www.sassmeister.com/gist/700f0721fd7940c84435cb1b5210f5d7

Answer

A couple of things I noticed that could do with some fixing

  • If you want the function to return a list like the one in $ms-range you shouldn't be returning in each iteration but rather return a list that's generated at the end of the loop

  • This part of your code 'calc($i * 1.2) $min / 16 * 1em' will always return a string and will not perform any calculations so it's best to just perform necessary calculations

  • When you use length($name) in your code, I'm assuming that part of the code is referring to length(s), length(sm) and so on. This will always return 1 because it will be interpreted as a list with just one item. Instead you should use str-length which will return the length of the string characters.

I also don't fully grasp the purpose of your @if-@else statement as both contain the same code within their block @return 'calc($i * 1.2) $min / 16 * 1em'

With my understanding of what you're trying to accomplish, the code should look like this

breakpoints: (  s: (320, 479),
                sm: (480, 767),
                 m: (768, 1023),
                 l: (1024, 1439),
                xl: (1440, null));

@function returnThatMap() {
  $map: ();
  @each $name, $values in $breakpoints {
    $min: nth($values, 1); //This assumes that the first value is always the minimum
    // $min: min($values...); //This in built function can find the minimum between two values as long as they are both integers and might be a better option
    $key: str-length($name) * 1.2;
    $value: ($min / 16) * 1em;
    $map: append($map, ($key $value), comma);
  }
  @return $map;
}

$ms-range : returnThatMap() ;

@debug $ms-range; // 1.2 20em, 2.4 30em, 1.2 48em, 1.2 64em, 2.4 90em}

Hope this helps