123

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?

1
  • Less has this feature but no, Sass doesn't. Commented Feb 5, 2024 at 22:46

7 Answers 7

118

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; }
Sign up to request clarification or add additional context in comments.

5 Comments

Note that this is still not "dynamic variables". This just a variation on using a list of lists that we've been using since forever.
This actually expands upon lists, which only accept an index number as the specifying variable. It allows for the variables to be called with a dynamically generated name, created by concatenation of a passed string, which was the requested functionality.
This should be the accepted answer. Although not completely dynamic, this mimics the requested functionality best.
While useful, this example is not creating any variables at all
True. Despite the title of the op's question, its text did not describe the creation of variables, so I did not address that. However, just added a section relative to doing that (albeit still with maps, not singular variables).
67

Sass does not allow variables to be created or accessed dynamically. However, you can use lists for similar behavior.

scss:

$list: 20px 30px 40px;    
@mixin get-from-list($index) {
  width: nth($list, $index);
}

$item-number: 2;
#smth {
  @include get-from-list($item-number);
}

css generated:

#smth {
  width: 30px; 
}

1 Comment

@castus how did this solve your problem? I'm running into a very similar issue where I need to take a string value from a list and add a $ to it and use it as a variable.
5

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);
}

4 Comments

I think this is exactly what I'm looking for. This is essentially taking the value passed in to the mixin and running it through the function. Then, depending on a series of if statements, returns the same string value as a variable. Would it be possible to do this with a potentially infinite number of values? Let's say we have a list of many strings, not just foo or bar.
This is pure bad practice, you don't want to end up with an endless chain of if conditions. Use SASS maps with key value pairs and pull the values from it instead.
It is mainly redundant in this showcase - why wouldn't you call just @include do-this($foo); ? ...however this would make sense, if the function actually did something, but it does only passing...
@jave.web - SCSS functions are superiors to mixins when you only need the value and for a given property. You will use a mixin where both the property and the value are to be used in multiple places, or the mixin is outputting more than one property.
2

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%);
  }
}

1 Comment

This answer does not answer the question. you are generating CSS, not SCSS...
1

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;
}

1 Comment

OP never specified they are using rails.
0

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

Comments

-2

To make a dynamic variable is not possible in SASS as of now, since you will be adding/connecting another var that needs to be parsed once when you run the sass command.

As soon as the command runs, it will throw an error for Invalid CSS, since all your declared variables will follow hoisting.

Once run, you can't declare variables again on the fly

To know that I have understood this, kindly state if the following is correct:

you want to declare variables where the next part (word) is dynamic

something like

$list: 100 200 300;

@each $n in $list {
    $font-$n: normal $n 12px/1 Arial;
}

// should result in something like

$font-100: normal 100 12px/1 Arial;
$font-200: normal 200 12px/1 Arial;
$font-300: normal 300 12px/1 Arial;

// So that we can use it as follows when needed

.span {
    font: $font-200;
    p {
       font: $font-100
    }
}

If this is what you want, I am afraid as of now, this is not allowed

4 Comments

Unfortunately this not working: error scss/components.scss (Line 71: Invalid CSS after " $font-": expected ":", was "$n: normal $n 1...")
@castus, oops! sorry for not being clear - I am not giving a solution, rather explaining the question once again
probably shouldnt post a solution that is not allowed!
i width this would work but seems we can't create variables via sass ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.