210
votes

I am writing a mixin like this:

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
    -webkit-box-shadow: $top $left $blur $color $inset;
    -moz-box-shadow: $top $left $blur $color $inset;
    box-shadow: $top $left $blur $color $inset;
}

When called what I really want is that if no $inset value is passed, nothing is output, rather than it compiling to something like this:

-webkit-box-shadow: 2px 2px 5px #555555 "";
-moz-box-shadow: 2px 2px 5px #555555 "";
box-shadow: 2px 2px 5px #555555 "";

How do I rewrite the mixin so that if there is no value of $inset passed, nothing is output?

13
It's a shame that SASS doesn't have a blank or nil value.Joshua Pinter
Btw, while looking at a different SASS limitation, I came across a nice way to get rid of the quotes in these situations. I added an answer for it.Joshua Pinter
Now in 2015 you can just use null in order to skip attr/prop. ie @include box-shadow($top, $left, $blur, $color, null)Drops

13 Answers

268
votes

A DRY'r Way of Doing It

And, generally, a neat trick to remove the quotes.

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  -webkit-box-shadow: $top $left $blur $color #{$inset};
  -moz-box-shadow:    $top $left $blur $color #{$inset};
  box-shadow:         $top $left $blur $color #{$inset};
}

SASS Version 3+, you can use unquote():

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  -webkit-box-shadow: $top $left $blur $color unquote($inset);
  -moz-box-shadow:    $top $left $blur $color unquote($inset);
  box-shadow:         $top $left $blur $color unquote($inset);
} 

Picked this up over here: pass a list to a mixin as a single argument with SASS

85
votes

A so much better DRY way

is to pass $args... to the @mixin. That way, no matter how many $args you will pass. In the @input call, you can pass all args needed. Like so:

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

And now you can reuse your box-shadow in every class you want by passing all needed args:

.my-box-shadow {
  @include box-shadow(2px 2px 5px #555, inset 0 0 0);
}
49
votes

Sass supports @if statements. (See the documentation.)

You could write your mixin like this:

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  @if $inset != "" {
    -webkit-box-shadow:$top $left $blur $color $inset;
    -moz-box-shadow:$top $left $blur $color $inset;
    box-shadow:$top $left $blur $color $inset;
  }
}
27
votes

You can put the property with null as a default value and if you don't pass the parameter it will not be interpreted.

@mixin box-shadow($top, $left, $blur, $color, $inset:null) {
  -webkit-box-shadow: $top $left $blur $color $inset;
  -moz-box-shadow:    $top $left $blur $color $inset;
  box-shadow:         $top $left $blur $color $inset;
}

This means you can write the include statement like this.

@include box-shadow($top, $left, $blur, $color);

Instead of writing it like this.

@include box-shadow($top, $left, $blur, $color, null);

As shown in the answer here

14
votes

Old question, I know, but I think this is still relevant. Arguably, a clearer way of doing this is to use the unquote() function (which SASS has had since version 3.0.0):

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  -webkit-box-shadow: $top $left $blur $color unquote($inset);
  -moz-box-shadow: $top $left $blur $color unquote($inset);
  box-shadow: $top $left $blur $color unquote($inset);
}

This is roughly equivalent to Josh's answer, but I think the explicitly named function is less obfuscated than the string interpolation syntax.

13
votes

I know its not exactly the answer you were searching for but you could pass "null" as last argument when @include box-shadow mixin, like this @include box-shadow(12px, 14px, 2px, green, null); Now, if that argument is only one in that property than that property (and its (default) value) won't get compiled. If there are two or more args on that "line" only ones that you nulled won't get compiled (your case).

CSS output is exactly as you wanted it, but you have to write your nulls :)

  @include box-shadow(12px, 14px, 2px, green, null);

  // compiles to ...

  -webkit-box-shadow: 12px 14px 2px green;  
  -moz-box-shadow: 12px 14px 2px green;  
  box-shadow: 12px 14px 2px green;
8
votes

here is the solution i use, with notes below:

@mixin transition($trans...) {
  @if length($trans) < 1 {
    $trans: all .15s ease-out;
  }
  -moz-transition: $trans;
  -ms-transition: $trans;
  -webkit-transition: $trans;
  transition: $trans;
}

.use-this {
  @include transition;
}

.use-this-2 {
  @include transition(all 1s ease-out, color 2s ease-in);
}
  • prefer passing property values as native css to stay close to "the tongue"
  • allow passing variable number of arguments
  • define a default value for laziness
4
votes

Even DRYer way!

@mixin box-shadow($args...) {
  @each $pre in -webkit-, -moz-, -ms-, -o- {
    #{$pre + box-shadow}: $args;
  } 
  #{box-shadow}: #{$args};
}

And now you can reuse your box-shadow even smarter:

.myShadow {
  @include box-shadow(2px 2px 5px #555, inset 0 0 0);
}
3
votes

With [email protected] :

// declare
@mixin button( $bgcolor:blue ){
    background:$bgcolor;
}

and use without value, button will be blue

//use
.my_button{
    @include button();
}

and with value, button will be red

//use
.my_button{
    @include button( red );
}

works with hexa too

2
votes
@mixin box-shadow($left: 0, $top: 0, $blur: 6px, $color: hsla(0,0%,0%,0.25), $inset: false) {
    @if $inset {
        -webkit-box-shadow: inset $left $top $blur $color;
        -moz-box-shadow: inset $left $top $blur $color;
        box-shadow: inset $left $top $blur $color;
    } @else {
        -webkit-box-shadow: $left $top $blur $color;
        -moz-box-shadow: $left $top $blur $color;
        box-shadow: $left $top $blur $color;
    }
}
1
votes

Super simple way

Just add a default value of none to $inset - so

@mixin box-shadow($top, $left, $blur, $color, $inset: none) { ....

Now when no $inset is passed nothing will be displayed.

1
votes

You can always assign null to your optional arguments. Here is a simple fix

@mixin box-shadow($top, $left, $blur, $color, $inset:null) { //assigning null to inset value makes it optional
    -webkit-box-shadow: $top $left $blur $color $inset;
    -moz-box-shadow: $top $left $blur $color $inset;
    box-shadow: $top $left $blur $color $inset;
}
-1
votes

I am new to css compilers, hope this helps,

        @mixin positionStyle($params...){

            $temp:nth($params,1);
            @if $temp != null{
            position:$temp;
            }

             $temp:nth($params,2);
            @if $temp != null{
            top:$temp;
            }

             $temp:nth($params,3);
            @if $temp != null{
            right:$temp;
            }

             $temp:nth($params,4);
            @if $temp != null{
            bottom:$temp;
            }

            $temp:nth($params,5);
            @if $temp != null{
            left:$temp;
            }

    .someClass{
    @include positionStyle(absolute,30px,5px,null,null);
    }

//output

.someClass{
position:absolute;
 top: 30px;
 right: 5px;
}