Search code examples
variablessassconcatenationstring-interpolation

SASS / SCSS: Interpolate variable from string / name


Is it possible to get a variable by name?

I tried building the following function, but it's not working as expected...

@function variable-lookup($variable, $suffix: "") {
  $value: null;
  @if ($suffix != "" and global-variable-exists($variable+"-"+$suffix)) {
    $value: #{$variable+"-"+$suffix};
  }
  @else if (global-variable-exists($variable)) {
    $value: #{$variable};
  }
  @return $value;
}

Here's an example of how it might be used:

$primary: #000;
$primary-hover: blue;

a {
  color: variable-lookup("primary", "base");

  &:hover {
    color: variable-lookup("primary", "hover");
  }
}

The real power would come in when I want to write a bunch of context-specific, shorthand wrapper functions around this "variable-lookup" function.

Any ideas how to achieve this?


Solution

  • Trying to interpolate #{$variable+"-"+$suffix} to give the value primary-base and further trying to get the value of same variable name is not possible. primary-base is already a value and and can't be interpreted as a variable name. That sort of thing could lead to a lot of chaos.

    For what you want to accomplish, you are better of using a map and checking for the key in that map

    $colours: (
      'primary': red,
      'primary-base': blue
    );
    
    @function variable_lookup($colour, $suffix: '') {
      $value: null;
      @if ( $suffix != '' and map-has-key($colours, unquote($colour+'-'+$suffix)) ) {
        $value: map-get($colours, unquote($colour+'-'+$suffix));
      } @else if ( map-has-key($colours, unquote($colour)) ) {
        $value: map-get($colours, unquote($colour));
      }
      @return $value;
    }
    
    div {
      color: variable-lookup(primary, base);
    }
    
    p {
      color: variable-lookup(primary);
    }
    

    This compiles to the following css

    div {
      color: blue; }
    
    p {
      color: red; }
    

    Your code stored colours as variables but I used those names as keys in maps

    This allowed to simulate the checking of variables in your code using the map-has-key method. If that returns true, the key exists and we can get the value which in this case would be the colour using map-get

    UPDATED ANSWER
    One way to address the issues you raised in your comments would be to define the variables and use them in as values in the map

    $primary: #fff;
    $warning: yellow; 
    
    $colours: ( primary: $primary, 
                primary-hover: darken($primary, 5%), 
                secondary: $warning, 
                secondary-hover: darken($warning, 5%) );
    

    Another way would be to iterate through two lists and map colour to a style

    $colours: ();
    
    $list: primary success warning; //map primary to blue, success to green and so on
    $shades: blue green yellow;
    
    @for $i from 1 through length($list) {
      $key: nth($list, $i);
      $value: nth($shades, $i);
      $colours: map-merge($colours, ($key: $value));
      $colours: map-merge($colours, (unquote($key+'-hover'): darken($value, 5% )) );
    }
    
    @debug $colours // (primary: blue, primary-hover: #0000e6, success: green, success-hover: #006700, warning: yellow, warning-hover: #e6e600)
    

    The variable_lookup function remains the same.

    Hope this is able to help