'Creating or referencing variables dynamically in Sass

I'm trying to use string interpolation on my variable to reference another variable:

// Set up variable and mixin
$foo-baz: 20px;

@mixin do-this($bar) {
    width: $foo-#{$bar};
}

// Use mixin by passing 'baz' string as a param for use $foo-baz variable in the mixin
@include do-this('baz');

But when I do this, I get the following error:

Undefined variable: "$foo-".

Does Sass support PHP-style variable variables?



Solution 1:[1]

This is actually possible to do using SASS maps instead of variables. Here is a quick example:

Referencing dynamically:

$colors: (
  blue: #007dc6,
  blue-hover: #3da1e0
);

@mixin colorSet($colorName) {
    color: map-get($colors, $colorName);
    &:hover {
        color: map-get($colors, #{$colorName}-hover);
    }
}
a {
    @include colorSet(blue);
}

Outputs as:

a { color:#007dc6 }
a:hover { color:#3da1e0 }

Creating dynamically:

@function addColorSet($colorName, $colorValue, $colorHoverValue: null) {
  $colorHoverValue: if($colorHoverValue == null, darken( $colorValue, 10% ), $colorHoverValue);

  $colors: map-merge($colors, (
    $colorName: $colorValue,
    #{$colorName}-hover: $colorHoverValue
  ));

  @return $colors;
}

@each $color in blue, red {
  @if not map-has-key($colors, $color) {
    $colors: addColorSet($color, $color);
  }
  a {
    &.#{$color} { @include colorSet($color); }
  }
}

Outputs as:

a.blue { color: #007dc6; }
a.blue:hover { color: #3da1e0; }
a.red { color: red; }
a.red:hover { color: #cc0000; }

Solution 2:[2]

Anytime I need to use a conditional value, I lean on functions. Here's a simple example.

$foo: 2em;
$bar: 1.5em;

@function foo-or-bar($value) {
  @if $value == "foo" {
    @return $foo;
  }
  @else {
    @return $bar;
  }
}

@mixin do-this($thing) {
  width: foo-or-bar($thing);
}

Solution 3:[3]

Here's another option if you're working with rails, and possibly under other circumstances.

If you add .erb to the end of the file extension, Rails will process erb on the file before sending it to the SASS interpreter. This gives you a can chance to do what you want in Ruby.

For example: (File: foo.css.scss.erb)

// Set up variable and mixin
$foo-baz: 20px; // variable

<%
def do_this(bar)
  "width: $foo-#{bar};"
end
%>

#target {
  <%= do_this('baz') %>
}

Results in the following scss:

// Set up variable and mixin
$foo-baz: 20px; // variable

#target {
  width: $foo-baz;
}

Which, of coarse, results in the following css:

#target {
  width: 20px;
}

Solution 4:[4]

I came across the need to reference a colour dynamically recently.

I have a _colours.scss file for every project, where I define all my colours once and reference them as variables throughout.

In my _forms.scss file I wanted to setup button styles for each colour available. Usually a tedious task. This helped me to avoid having to write the same code for each different colour.

The only downside is that you have to list each colour name and value prior to writing the actual css.

// $red, $blue - variables defined in _colours.scss
$colours: 
  'red' $red,
  'blue' $blue;

@each $name, $colour in $colours {
  .button.has-#{$name}-background-color:hover {
    background-color: lighten($colour, 15%);
  }
}

Solution 5:[5]

I needed to use dynamic color values in sass variables. After lots of search, I applied this solution:

In application.html.erb:

<style>
  :root {
    --primary-color: <%= current_client.header_color %>;
    --body-color: <%= current_client.footer_color %>;
   }
</style>

In variables.sass:

$primary: var(--primary-color);

And boom you are good to go!

Reference: https://medium.com/angular-in-depth/build-truly-dynamic-theme-with-css-variables-539516e95837

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sjeiti
Solution 2 Adam Stacoviak
Solution 3 Blake Taylor
Solution 4 lukeseager
Solution 5 Seemab Mehmood