16

I want to merge a variable and a string to a new variable, like the following:

$product_bodyclass_list: class1 class2 class3 class4;

$product_class1_color: #C00;
$product_class2_color: #00C;
$product_class3_color: #0C0;
$product_class4_color: #000;

@each $bodyclass in $product_bodyclass_list {
    .page-#{$bodyclass} {
        a {
            color: $product_#{$bodyclass}_color; // This is wrong
        }
    }
}

Does anybody know how to do this?

sneeky
  • 1,458
  • 2
  • 13
  • 19

2 Answers2

27

No, you can't have dynamic variables.

From the docs:

You can also use SassScript variables in selectors and property names using #{} interpolation

You can accomplish the same effect using two lists and the nth() function.

$products: class1, class2, class3, class4;    
$product_colors: #C00, #00C, #0C0, #000;

$i: 1;
@each $class in $products {
    .page-#{$class} {
        a {
            color: nth($product_colors, $i)
        }
    }
  $i: $i + 1;
}

Also, it might be cleaner to use the @for directive:

@for $i from 1 through length($products) {
    .page-#{nth($products, $i)} {
        a {
            color: nth($product_colors, $i)
        }
    }
}

In addition, if you want to define the variables explicitly so you can use them elsewhere, make a list of variables:

$product_class1_color: #C00;
$product_class2_color: #00C;
$product_class3_color: #0C0;
$product_class4_color: #000;

$product_colors: $product_class1_color, $product_class2_color, $product_class3_color, $product_class4_color;
bookcasey
  • 39,223
  • 13
  • 77
  • 94
4

UPDATE: Sass maps make this answer pretty much obsolete.

Another option is to use one list, with two elements each, and use it as a hashmap.

$products: class1 #C00, class2 #00C, class3 #0C0, class4 #000;

@each $kvp in $products { // kvp stands for 'key-value pair'
    .page-#{nth($kvp, 1)} {
        a {
            color: nth($kvp, 2);
        }
    }
}

I like to make simple functions to make the meaning of my code clearer. I'd probably do something more like:

@function kvp-key($kvp) {
    @return nth($kvp, 1);
}

@function kvp-value($kvp) {
    @if length($kvp) == 2 {
        @return nth($kvp, 2);
    } @else {
        @warn "argument was not a key-value pair";
        @return null;
    }
}

And then I'd reimplement the loop like this:

@each $kvp in $products { // kvp stands for 'key-value pair'
    .page-#{kvp-key($kvp)} {
        a {
            color: kvp-value($kvp);
        }
    }
}

We haven't saved any lines, but we've made the intent of the loop a bit clearer.

Paul d'Aoust
  • 3,019
  • 1
  • 25
  • 36