25

I'm new with Sass stuff and I've been reading about different ways to use variables. This principle I'm trying to apply is just for colors, and some of the solutions I've found were something like this (map-get):

$colors: (
    lighestGray: #F8F8FA,
    lightGray: #A5ACBA,
    light: #FFFFFF,
    dark: #000000,
    link: #428bca,
    linkHover: #555,
    navBlue: #7AC243,
    navGreen: #009CDC,
);

Then you use it on your class like this:

.my-class {
    color: map-get($colors, dark);
}

And the other way is to use:

$color-black: #000000;

Then you use it like this:

.my-class {
    color: $color-black;
}

Which option is better? Or does the map-get function have another purpose? Has Sass a pattern for this or does it depend on each web developer?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex
  • 879
  • 2
  • 10
  • 20
  • 1
    They both produce the same CSS, so it's more of a preference than anything else. – André Dion Aug 31 '16 at 16:21
  • But what happend in case you are styling each border side color? ex. `.border-color { map-get($colors, color1); map-get($colors, color2); map-get($colors, color3); map-get($colors, color4); } `isn't this inefficient? – Alex Aug 31 '16 at 16:24
  • @Alex - you're supposed to wrap that in a SASS utility function, which is specific to colors, to avoid messy code such as the one you put. – vsync Nov 07 '16 at 14:55

4 Answers4

31

The differences is that when you use $map variables, they are best designed for using through iterations or using @each.

Sample case:

SCSS

// Map variable
$icons: (
  facebook   : "\f0c4",
  twitter    : "\f0c5",
  googleplus : "\f0c6",
  youtube    : "\f0c7"
);

// Mixin doing the magic
@mixin icons-list($map) {
  @each $icon-name, $icon in $map {
    @if not map-has-key($map, $icon-name) {
      @warn "'#{$icon-name}' is not a valid icon name";
    }

    @else {
      &--#{$icon-name}::before {
        content: $icon;
      }
    } 
  }
}

// How to use it
.social-link {
    background-color: grey;
    @include icons-list($icons);
}

CSS

// CSS Output

.social-link {
  background-color: grey;
}
.social-link--facebook::before {
  content: "";
}
.social-link--twitter::before {
  content: "";
}
.social-link--googleplus::before {
  content: "";
}
.social-link--youtube::before {
  content: "";
}

This code was taken from my own answer in the following post but the answer is a case use of @each :)

Hope this help you

Community
  • 1
  • 1
Héctor León
  • 2,210
  • 2
  • 23
  • 36
  • Isn't `@if not map-has-key($map, $icon-name) {` a bit redundant? – goonerify Feb 03 '21 at 08:47
  • @goonerify maybe now its is, some compilers complain if you try to use a $map variable with a wrong key, others just ignore that entire line. So i added as a terminal warning. No really neccessary – Héctor León Feb 03 '21 at 09:07
3

Example making a theme with css variables with fallback color see codepen css variables

// VARS (FOR FALLBACK)
// -------------------
$theme-base: #70c1ac;
$theme-base-aa: adjust-color($theme-base, $blue: 125);

// PROCESSED THEME
$theme-color: $theme-base;
$theme-color-dark: darken($theme-color, 20%);
$theme-color-light: lighten($theme-color, 20%);
$theme-color-mixed: mix(#fff, $theme-color, 75%);
$theme-color-trans: transparentize($theme-color, .4);

// PROCESSED SECONDARY
$theme-color-aa: $theme-base-aa;
$theme-color-aa-dark: darken($theme-color-aa, 20%);
$theme-color-aa-light: lighten($theme-color-aa, 20%);
$theme-color-aa-mixed: mix(#fff, $theme-color-aa, 75%);
$theme-color-aa-trans: transparentize($theme-color-aa, .4);

$theme-colors: (
  "aa-dark": $theme-color-aa-dark,
  "aa-light": $theme-color-aa-light,
  "aa-mixed": $theme-color-aa-mixed,
  "aa-trans": $theme-color-aa-trans,
  aa: $theme-color-aa,
  dark: $theme-color-dark,
  light: $theme-color-light,
  mixed: $theme-color-mixed,
  theme: $theme-color,
  trans: $theme-color-trans,
);

@mixin themeColor ($prop, $color: null) {
  @if ($color) {
    #{$prop}: map-get($theme-colors, $color);
    #{$prop}: var(--theme-color-#{$color})
  } @else {
    #{$prop}: map-get($theme-colors, theme);
    #{$prop}: var(--theme-color);
  }
}

@mixin setThemeColors($base1: "", $base2: "") {
  // BASE THEME COLORS
  $color-base: $theme-base;
  $color-aa: $theme-base-aa;

  @if ($base1) {
    $color-base: $base1;
    $color-aa: $base2;
  }

  // PROCESSED THEME COLORS
  $color-aa-dark: darken($color-aa, 20%);
  $color-aa-light: lighten($color-aa, 20%);
  $color-aa-mixed: mix(#fff, $color-aa, 75%);
  $color-aa-trans: transparentize($color-aa, .5);
  $color-aa: $color-aa;
  $color-dark: darken($color-base, 20%);
  $color-light: lighten($color-base, 20%);
  $color-mixed: mix(#fff, $color-base, 75%);
  $color-trans: transparentize($color-base, .5);

  // CSS VARIABLES
  --theme-color-aa-dark: #{$color-aa-dark};
  --theme-color-aa-light: #{$color-aa-light};
  --theme-color-aa-trans: #{$color-aa-trans};
  --theme-color-aa: #{$color-aa};
  --theme-color-dark: #{$color-dark};
  --theme-color-light: #{$color-light};
  --theme-color-mixed: #{$color-mixed};
  --theme-color-trans: #{$color-trans};
  --theme-color: #{$color-base};
}

:root {
  @include setThemeColors($theme-base, $theme-base-aa);
}

body {
  @include themeColor("background","mixed");
  font-size: 2rem;
}

ul {
  list-style: none; /* Remove default bullets */
}

ul li::before {
  content: "\2022";  /* Add content: \2022 is the CSS Code/unicode for a bullet */
  @include themeColor("color","dark");

  font-weight: bold; /* If you want it to be bold */
  display: inline-block; /* Needed to add space between the bullet and the text */ 
  width: 1.2em; /* Also needed for space (tweak if needed) */
  margin-left: -.8em; /* Also needed for space (tweak if needed) */
}

li {
  @include themeColor("color", "light");
  @include themeColor("background", "aa-dark");
}
Ron Jonk
  • 706
  • 6
  • 16
2

Why pick one when you can have them both.

_variables.scss

$color0 : white;
$color1 : red;
$color2 : green;
$color3 : blue;

_lists.scss

@use "variables";
@use "sass:map";
@use "sass:meta";
@use "sass:list";

@function dynamic($variable){
    $i: 0;
    $list: ();
    @while(variable-exists($variable + $i)){
        $list: list.append($list, map.get(meta.module-variables(variables), $variable + $i));
        $i: $i + 1;
    }
    @return $list;
}

$colors: dynamic('color'); // white red green blue

Import both into your scss files and use the list when you need to loop and the variables for shorthand when applying styles.

Mike Mellor
  • 1,316
  • 17
  • 22
1

map-get is used for getting a CSS value from more kinds of object.

Suppose you have $param where you have defined multiple properties and now you want to assign. You can use it in the following ways -

color: map-get($params, "color");

Whereas a simple variable holds only a single value.

map-get to get css value from object holding multiple values whereas variable to hold single value

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Samyak Jain
  • 856
  • 1
  • 9
  • 12