29
votes

I have a list in SASS, and I'm trying to access on of the items by using bracket notation:

$collection[1];

but that gives me an error.

Is there any other way to do this?


Why do I want to do this?

I have a list of colors that have to be set on different elements according to a colors assigned to them by the server. The markup has numbered classes (color-0, color-1, etc.). Here's the CSS I'm aiming for:

.color-0 { color: red }
.color-1 { color: orange }
.color-2 { color: green }
.color-3 { color: blue }
/* many more, with more complex colors... */

Instead of writing it all by hand, I figured I could use a SASS collection with a loop:

$color-collection: ('red', 'orange', 'green', 'blue');
$color-count: length($color-collection);

@for $i from 0 to $color-count {
    .color-#{$i} {
        color: $color-collection[ $i ];
    }
}

but this just gives me the following error:

Syntax error: Invalid CSS after "...color-collection": expected ";", was "[ $i ];"


How can I accomplish this?

4
Not exactly the same as your case, but method should prove useful: stackoverflow.com/questions/14695965/… (use @each)steveax
@steveax - Ugh! That's exactly what I'm trying to avoid. I might potentially have upwards of 30 colors in there. Listing them all out twice like just makes me want to go right back to vanilla CSS; I think that's much neater.MegaHit
you wouldn't have to list them out twice, just put the color names/values in $color-collection like you have them, and you and spin through them with @each. In the case of the question I linked, he needed them as vars too which you don't need. There's a few ways to skin that cat and bookcasey's answer is good.steveax

4 Answers

43
votes
$color-collection: ('red', 'orange', 'green', 'blue');

@for $i from 0 to length($color-collection) {
    .color-#{$i} {
        color: unquote(nth($color-collection, $i+1));
    }
}

Use nth(), also unquote() if you want to pass quoted strings.

Though, I personally wouldn't:

$color-collection: (red, rgba(50,50,80, .5), darken(green, 50%), rgba(blue, .5));

@for $i from 0 to length($color-collection) {
    .color-#{$i} {
        color: nth($color-collection, $i+1);
    }
}

Because then you can pass any color object.

6
votes

You can use @each rule instead of @for, which is more semantic, faster, and it makes the code shorter:

$color-collection: (red, orange, green, blue);

@each $color in $color-collection {
    .color-#{$color} {
        color: $color;
    }
}

Or if you prefer you can use $color-collection list directly into the @each directive:

@each $color in red, orange, green, blue {
    .color-#{$color} {
        color: $color;
    }
}

As @bookcasey says is preferable to use unquoted strings because then you can pass any color object or function

Sass reference for @each directive

3
votes

just came across this and tested bookcasey's answer, which works well but I wanted to use the color name as the class instead; I found that this code works as I needed.

$colors: ( 'black', 'white', 'red', 'green', 'blue' );

@for $i from 0 to length($colors) {
    $thisColor: unquote(nth($colors, $i+1));
    .color-#{$thisColor} {
        color: $thisColor;
    }
}

using the #{...} allows you to use functions as well, so if you need to use an arbitrary name that may not be used directly in the rules you could use

@for $i from 0 to length($colors) {
    .color-#{unquote(nth($colors, $i+1))} {
        // some rules that don't actually use the var
        // so there's no need to cache the var
    }
}

output:

.color-black { color: black; }
.color-white { color: white; }
.color-red { color: red; }
// etc..

Hope this helps someone else!

1
votes

I had similar problem and tried Alex Guerrero solution. Didn't work form me cause output was like .color-gray:{gray}; instead of .color-1:{gray};.So I modified it a bit and it looks like this:

$color-pallete: (gray, white, red, purple)

$i: 0
@each $color in $color-pallete
    .color-#{$i}
        color: $color
    $i: $i + 1

Oh, ye. I use SASS, not SCSS.