csssasscompass-sass

Looping through two @each lists in SCSS


In my CSS I have to create classes that make reference to a 'hair colour' and 'hairstyle'

I have written a mixin to help make my CSS writing more efficient:

@mixin hair($hair, $colour) {
    .hair-#{$colour} .#{$hair}  { 
background:image-url("xsppsfhair#{$hair}#{$colour}.svg") center top no-repeat, 
image-url("xsppsheadgrey.svg") center top no-repeat, 
image-url("xsppsbhair#{$hair}#{$colour}.svg") center top no-repeat;
}


}

@include hair(spikyboy, blonde);    
@include hair(curlyafroboy, blonde);    

This produces the following CSS

.hair-blonde .spikyboy {
  background: url('../images/xsppsfhairspikyboyblonde.svg?1348681869') center top no-repeat, url('../images/xsppsheadgrey.svg?1348834673') center top no-repeat, url('../images/xsppsbhairspikyboyblonde.svg?1348682005') center top no-repeat;
}

.hair-blonde .curlyafro {
  background: url('../images/xsppsfhaircurlyafroblonde.svg?1348681869') center top no-repeat, url('../images/xsppsheadgrey.svg?1348834673') center top no-repeat, url('../images/xsppsbhaircurlyafroblonde.svg?1348682005') center top no-repeat;
}

This is great, but as I have a total combination of 35 hair colours and hair styles, I still end up with way too many @includes.

On this page, it says SASS has an @each which can be used to loop through lists. There is a further example here. However, both these examples only show looping through 1 list. Is it possible to loop through two lists?

I have tried many variations of my code, but none seem to work. I thought the following would definitely work, but I just get an error message about $colour being undefined.

$hairstyle: (red, blonde, ltbrown);
$haircolour: (red, blonde, ltbrown);

    @each $hair in $haircolour, $colour in $haircolour {
    .hair-#{$colour} .#{$hair}  {
background:image-url("xsppsfhair#{$hair}#{$colour}.svg") center top no-repeat, 
image-url("xsppsheadgrey.svg") center top no-repeat, 
image-url("xsppsbhair#{$hair}#{$colour}.svg") center top no-repeat;
    }

    .girl.hair-#{$colour} #eyelash {
        background: image-url("xsppseyelash#{$colour}.svg") center top no-repeat;
    }
}

Could someone please give me some pointers as to what I am doing wrong?


Solution

  • What you need to do is create a loop inside the first loop (I've simplified a bit so it's easier to see):

    @mixin style-matrix($colors, $styles) {
        @each $s in $styles {
            @each $c in $colors {
                .#{$s} .#{$c} {
                    background:image-url("xsppsfhair-#{$s}-#{$c}.svg");
                }
            }
        }
    }
    
    $colors: blonde, brunette, auburn;
    $styles: beehive, pixie, bob;
    @include style-matrix($colors, $styles);
    

    You get this output:

    .beehive .blonde {
      background: image-url("xsppsfhair-beehive-blonde.svg");
    }
    
    .beehive .brunette {
      background: image-url("xsppsfhair-beehive-brunette.svg");
    }
    
    .beehive .auburn {
      background: image-url("xsppsfhair-beehive-auburn.svg");
    }
    
    .pixie .blonde {
      background: image-url("xsppsfhair-pixie-blonde.svg");
    }
    
    .pixie .brunette {
      background: image-url("xsppsfhair-pixie-brunette.svg");
    }
    
    .pixie .auburn {
      background: image-url("xsppsfhair-pixie-auburn.svg");
    }
    
    .bob .blonde {
      background: image-url("xsppsfhair-bob-blonde.svg");
    }
    
    .bob .brunette {
      background: image-url("xsppsfhair-bob-brunette.svg");
    }
    
    .bob .auburn {
      background: image-url("xsppsfhair-bob-auburn.svg");
    }