lharby
lharby

Reputation: 3265

Pass variable to sass mixin to contain multiple properties

I have a sass mixin for box-shadow which looks like this:

@mixin box-shadow($hLength, $vLength, $blur, $spread, $colour, $type:""){
     @if $type != "" {
        -webkit-box-shadow:$type $hLength $vLength $blur $spread $colour;
        -moz-box-shadow:$type $hLength $vLength $blur $spread $colour;
        box-shadow:$type $hLength $vLength $blur $spread $colour;
    }
}

This has worked fine for most of my application.

However I now need to modify my method somehow.

I have list items which can have one of 11 classes, this class controls the colour and icon of the list item.

Examples of my variables:

$channel1:     #19BC9C;
$channel2:     #F1C40E;
$channel3:     #9B59B6;
$channel4:     #3398DB;

And my sass for the list items looks like this:

li {

   &.channel1 {
      @include box-shadow(-3px, 0px, 0px, 0px, $channel1, inset);
   }

   &.channel2 {
      @include box-shadow(-3px, 0px, 0px, 0px, $channel2, inset);
   }
}

The problem is that the px values and inset are the same for each class element. However there is no property for box-shadow-color, so I cannot split the parameters up.

I was hoping I could store -3px, 0px, 0px, 0px in a separate variable and pass that in.

@include box-shadow($channelBorder, $channel1, inset); etc, but this does not work.

Does anyone know if there is a decent solution, I would rather keep my mixin as it is, as much as possible.

Upvotes: 0

Views: 4337

Answers (1)

cimmanon
cimmanon

Reputation: 68309

One would typically solve this problem by using default values on a mixin and only specifying the exact values you wish to modify:

$default-hLength: -3px !default;
$default-vLength: 0 !default;
$default-blur: 0 !default;
$default-spread: null !default;
$default-colour: null !default;
$default-type: null !default;

@mixin box-shadow($hLength: $default-hLength, $vLength: $default-vLength, $blur: $default-blur, $spread: $default-spread, $colour: $default-colour, $type: $default-type){
    -webkit-box-shadow: $type $hLength $vLength $blur $spread $colour;
    -moz-box-shadow: $type $hLength $vLength $blur $spread $colour;
    box-shadow: $type $hLength $vLength $blur $spread $colour;
}

li {

   &.channel1 {
      @include box-shadow($colour: $channel1, $type: inset);
   }

   &.channel2 {
      @include box-shadow($colour: $channel2, $type: inset);
   }
}

Alternately, you can store portions of your arguments as a list and expand them when calling your mixin:

li {
    $vals1: -3px 0 0 0;
    $vals3: -3px 0 0 0 black inset;
    &.channel1 {
        // option 1
        @include box-shadow($vals1..., $colour: $channel1, $type: inset);
        // option 2
        @include box-shadow(join($vals1, ($channel1, inset))...);
        // option 3
        @include box-shadow(set-nth($vals3, 5, $channel1)...);
    }

    &.channel2 {
        // option 1
        @include box-shadow($vals1..., $colour: $channel2, $type: inset);
        // option 2
        @include box-shadow(join($vals1, ($channel2, inset))...);
        // option 3
        @include box-shadow(set-nth($vals3, 5, $channel2)...);
    }
}

However, you're never going to be satisfied with a mixin like that because it only assumes that you're going to have a single box-shadow, but the property allows for multiples.

It would be by far simpler for you in the long run if you could loop through the values you want and call a more robust mixin:

@mixin box-shadow($values...) {
    -webkit-box-shadow: $values;
    -moz-box-shadow: $values;
    box-shadow: $values;
}

li {
    $colours: $channel1, $channel2, $channel3, $channel4;

    @for $i from 1 through length($colours) {
        &.channel#{$i} {
            @include box-shadow(inset -3px 0 0 0 nth($colours, $i));
        }
    }
}

Upvotes: 1

Related Questions