47

I like to make mixins with SASS that help me make good cross-browser compatibility. I want to make a mixin that looks like this:

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

to which I can pass something like this:

@include box-shadow(inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5), inset 0px 0px 0px 1px #ff800f);

with the result being something like this:

box-shadow: inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5),inset 0px 0px 0px 1px #ff800f;
-moz-box-shadow: inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5),inset 0px 0px 0px 1px #ff800f;
-webkit-box-shadow: inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5),inset 0px 0px 0px 1px #ff800f; 

However, This doesn't work because the complier thinks I am trying to pass the mixin 3 arguments. box-shadow takes a variable number of comma separated bits, so I can't just define a mixin like box-shadow($1,$2,$3).

I tried passing

@include box-shadow("inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5), inset 0px 0px 0px 1px #ff800f");

and it compiled, but didn't actually render the styles.

Any tips on how to resolve this?

Arnaud Le Blanc
  • 98,321
  • 23
  • 206
  • 194
Oliver
  • 11,297
  • 18
  • 71
  • 121
  • Like you, I think it's intuitive to wrap the parameter in a string when there are commas. Putting the #{} in the mixin itself allows you to do this. I added an answer to show this as well. – Joshua Pinter Apr 02 '12 at 14:51
  • 2
    Just a note on the use of `rgba` mostly for others starting to use Sass (since I know everyone else here already knows this :]). Instead of having to type `rgba(0,0,0,0.5);` you can type `rgba(black,.5)`. Same goes with `white`, `red`, etc. and [all other CSS colors](http://www.cssportal.com/css3-color-names/), that way you don't have to type the actual RGB value itself. You can also use hex values: `rgba(#258,.5);`. Or color variables: `rgba($colorVariable,.5)`. Hope that helps. – Ricardo Zea Oct 23 '13 at 16:44
  • 4 years on I notice that the order of the box-shadow expressions is the wrong way around. How embarrassing. – Oliver Jul 14 '15 at 08:38

6 Answers6

74

Variable Arguments

Sometimes it makes sense for a mixin to take an unknown number of arguments. For example, a mixin for creating box shadows might take any number of shadows as arguments. For these situations, Sass supports “variable arguments,” which are arguments at the end of a mixin declaration that take all leftover arguments and package them up as a list. These arguments look just like normal arguments, but are followed by .... For example:

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

.shadows {
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}

via: http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#variable_arguments

rzar
  • 1,236
  • 1
  • 13
  • 9
  • 4
    Neato. This seems to be a new feature for SASS 3.2: http://chriseppstein.github.com/blog/2012/08/23/sass-3-2-is-released/ Released Aug 23 '12, so be careful if you're using an older SASS compiler. – Oliver Oct 25 '12 at 09:08
37

SASS 3.1 or less

Note: If you're using SASS 3.2+ then use the Variable Arguments feature as rzar suggests.

Just use string interpolation in the mixin itself, like so:

@mixin box-shadow($value) {
  -webkit-box-shadow: #{$value};               // #{} removes the quotation marks that
  -moz-box-shadow: #{$value};                  // cause the CSS to render incorrectly.
  box-shadow: #{$value};
}

// ... calling it with quotations works great ...
@include box-shadow("inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5), inset 0px 0px 0px 1px #ff800f");

Thanks for the tip Ryan.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
14

Use string interpolation

@include box-shadow(#{"inset -2px -2px 2px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.5), inset 0px 0px 0px 1px #ff800f"});
Ryan
  • 3,594
  • 1
  • 24
  • 23
4

There's many ways to do this, the best way is using a mixin like so:

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

And include it like this:

@include box-shadow(inset 0 1px 0 #FFD265, 0 0 0 1px #912E01, 0 0 0 7px rgba(0, 0, 0, .1), 0 1px 4px rgba(0, 0, 0, .6));

or

@mixin box-shadow($value) {
      -webkit-box-shadow: #{$value};               
      -moz-box-shadow: #{$value};          
      box-shadow: #{$value};
}

And include it like this:

@include box-shadow("inset 0 1px 0 #FFD265, 0 0 0 1px #912E01, 0 0 0 7px rgba(0, 0, 0, .1), 0 1px 4px rgba(0, 0, 0, .6)");

or:

@mixin box-shadow($value) {
      $value: unquote($value);
      -webkit-box-shadow: $value;               
      -moz-box-shadow: $value;          
      box-shadow: $value;
}

or:

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

And include it like this:

@include box-shadow((inset 0 1px 0 #FFD265, 0 0 0 1px #912E01, 0 0 0 7px rgba(0, 0, 0, .1), 0 1px 4px rgba(0, 0, 0, .6)));

Sass is very powerful :)

Shannon Hochkins
  • 11,763
  • 15
  • 62
  • 95
2

i want to point out that you can also pass a value using the argument name as you call the mixin:

@mixin shadow($shadow: 0 0 2px #000) {
    box-shadow: $shadow;
    -webkit-box-shadow: $shadow; 
    -moz-box-shadow: $shadow; 
}

.my-shadow {
  @include shadow($shadow: 0 0 5px #900, 0 2px 2px #000);
}

note that scss is scoped so $shadow will still retain its mixin value if used again later. less i believe, suffers from reassignment in this scenario

Doug Lee
  • 768
  • 8
  • 10
0

This doesn't compile:

+box-shadow(inset 0 1px 0 #FFD265, 0 0 0 1px #912E01, 0 0 0 7px rgba(0, 0, 0, .1), 0 1px 4px rgba(0, 0, 0, .6))

this compiles:

+box-shadow((inset 0 1px 0 #FFD265, 0 0 0 1px #912E01, 0 0 0 7px rgba(0, 0, 0, .1), 0 1px 4px rgba(0, 0, 0, .6)))

That is, add a parenthesis around the comma-separated list of shadows and it should work:

+box-shadow( (myshadow1, myshadow2, ...) )
Panagiotis Panagi
  • 9,927
  • 7
  • 55
  • 103
  • The docs http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#variable_arguments indicate that the first should be valid, so I guess there is a bug in your compiler. – Oliver Nov 13 '12 at 21:48