Search code examples
cssloopssasssass-maps

SASS : How to generate a map using a loop


My goal is to generate a SASS map to store variants of colors that are stored in the following map:

  $colors : (

    jet                 : #333333,
    wintergreen-dream   : #588C73,
    eton-blue           : #8FC0A9,
    sunglow             : #FFC33C,
    light-kaki          : #F2E394,
    bege                : #FAF3DD

  );

So far, I am using a @function to retrieve these variants:

  @function light       ($color, $val) { @return lighten($color, $val);     }
  @function dark        ($color, $val) { @return darken($color, $val);      }
  @function transparent ($color, $val) { @return transparent($color, $val); }


The map I am expecting to be able to generate would look alike the following:

  $colors-map : (

    eton-blue : (

        base  : $eton-blue,
        light : lighten($eton-blue, 15%),
        dark  : darken($eton-blue, 15%),
        trans : transparent($eton-blue, .5)


    ),

    jet : (

      base  : $jet,
      light : lighten($jet, 15%),
      dark  : darken($jet, 15%),
      trans : transparent($jet, .5)

    )

    // ...

  );


Yet, the loop I've already tried to apply, looks like this:

@for $key, $value in $colors {}

However, I was naive to believe it could work inside of the map itself.


Questions which answers could easier answer this doubt :

  • How to add values to a SASS map (function), (key:value) ?
  • Basic usage of map-merge/map-set ? (@return map-merge($map, $new))

Strictly what I am looking for below :

$alternative-colors : (

    @each $color, $hex in $colors {

        #{$color} : (

            light : lighten($color, 25%),
            dark  : darken($color, 25%)

        );

    }

);

But yet, it returns following error:

Error: Invalid CSS after \"...tive-colors : (\": expected \")\", was \"@each (...)

Conclusion

Long time have passed, and I it would be nice if I could share my solution with everyone else.

I have created a repo to store the results of this problem solving, https://github.com/vladimirlisovets/SASS-Color-Palettes.

Hope it to be useful to someone either to inspire for something better.

Cheers.


Solution

  • $colors : (
      jet                 : #333333,
      wintergreen-dream   : #588C73,
      eton-blue           : #8FC0A9,
      sunglow             : #FFC33C,
      light-kaki          : #F2E394,
      bege                : #FAF3DD
    );
    
    $colors-map: ();
    
    @function create_colour_map($color, $percentage, $opacity) {
      $map: (
        base: $color,
        light: lighten($color, $percentage),
        dark: darken($color, $percentage),
        trans: transparentize($color, $opacity)
      );
      @return $map;
    }
    
    @each $key, $value in $colors {
      $map: ();
      $map: map-merge($map, ($key: create_colour_map($value, 15%, 0.5)) );
      $colors-map: map-merge($colors-map, $map);
    }
    
    @debug $colors-map; //prints out the map below 
      (jet:               (base: #333333, 
                           light: #595959,
                           dark: #0d0d0d,
                           trans: rgba(51, 51, 51, 0.5)), 
       wintergreen-dream: (base: #588C73, 
                           light: #81b099,
                           dark: #3a5d4c,
                           trans: rgba(88, 140, 115, 0.5)),
       eton-blue:          (base: #8FC0A9,
                            light: #c0dccf,
                            dark: #5ea483,
                            trans: rgba(143, 192, 169, 0.5)), 
       sunglow:            (base: #FFC33C,
                            light: #ffdb89,
                            dark: #efa500,
                            trans: rgba(255, 195, 60, 0.5)),
       light-kaki:         (base: #F2E394,
                            light: #faf5d8,
                            dark: #ead150,
                            trans: rgba(242, 227, 148, 0.5)),
       bege:               (base: #FAF3DD,
                            light: white,
                            dark: #f0db9a,
                            trans: rgba(250, 243, 221, 0.5)))
    

    I merged your three functions into one, the create_colour_map function. It takes three arguments for the colour, percentage and opacity. The function returns a map

    Calling the create_colour_map(#333333, 15%, 0.5) with those args returns a map

    (base: #333333, 
     light: #595959,
     dark: #0d0d0d,
     trans: rgba(51, 51, 51, 0.5)
    );
    

    I just loop through the $colors map and each time call the function which generates a map that becomes the value of the key each time for an iteration.

    How to add values to a map and basic usage of map-merge?

    I use map-merge to add values to a map. Just as the name implies, it joins two maps together and since it is a function, it can be used where Sass expects a value. So take for example the code below

    $map: ( colour: red);
    $new_map: (class: blue);
    

    If we wanted $map to have the same keys and values as both maps, we could write

    $map: map-merge( $map, $new_map); // $map: (colour: red, class: blue)
    

    This is basically saying the return value of the function ( which would be the two maps joined together ) is the value of $map

    Simply put just think of that line of code as variable reassignment in programming languages. This is how you can use map-merge to set values in maps. The 2nd argument for the map-merge method doesn't need to be a predefined map variable. It could have been written this way

    $map: map-merge( $map, (class: blue) );
    

    So here it just looks like you're adding a new key and value to the $map variable