Tobi
Tobi

Reputation: 143

How can I have @if inside the value of a CSS property?

Is there a way to use Sass’ @if statement inside the value part of a property? I.e. make the following code work:

@mixin color-transition($color:true, $background:true, $border:true, $duration: 0.2s) {
    transition: 
        @if ($color) {
            color $duration linear,
        }
        @if ($background) {
            background-color $duration linear,
        }
        @if ($border) {
            border-color $duration linear,
        }
    ;
}

I can’t move transition: inside of the if clause because in that case the last of them would overwirte the former …

Upvotes: 1

Views: 81

Answers (3)

Niloct
Niloct

Reputation: 10015

@mixin color-transition($color:true, $background:true, $border:true, $duration: 0.2s) {
    $transition : '';
    @if ($color) {
        $transition : 'color #{$duration} linear,'
    }
    @if ($background) {
        $transition : '#{$transition} background-color #{$duration} linear,'
    }
    @if ($border) {
        $transition : '#{$transition} border-color #{$duration} linear,'
    }
    @if (str-length($transition) > 0) {
        transition: unquote(str-slice($transition, 1, -2));
    }
}

Then you can @include color-transition() in any CSS rule. Tested.

Edit

Now the property isn't showed if there is no transition, and bugs fixed.

Upvotes: 2

somethinghere
somethinghere

Reputation: 17358

You could simply concatenate the answer and print it afterwards...

@mixin color-transition($color:true, $background:true, $border:true, $duration: 0.2s) {
    $transition: ''; 
    @if ($color) {
        $transition: $transition + 'color #{$duration} linear';
    }
    @if ($background) {
        @if ($transition != ''){ $transition: $transition + ','; }
        $transition:  $transition + 'background-color #{$duration} linear';
    }
    @if ($border) {
        @if ($transition != ''){ $transition: $transition + ','; }
        $transition:  $transition + 'border-color #{$duration} linear ';
    }
    transition: unquote($transition);
}

But of course, you could just simply do it like this:

@mixin color-transition($color:0s, $background:0s, $border:0s){
    transition: color $color linear, background $background linear, border $border linear;
}

Which allows you to call them all in one go:

@include color-transition(1s,1s,2s);

With an output like this:

transition: color 1s linear, background 1s linear, border 2s linear;

Since the default is 0s, technically you have no transition set for those values, although it might overwrite preset values somewhere else, so I see why it might not be ideal, just an idea.

Upvotes: 2

cimmanon
cimmanon

Reputation: 68339

You can't use a control directive in the middle of a statement like that. You have to append a string or list variable inside of your @if statements and then write out the finished property at the very end.

Your specific use case would be best solved by passing in a list of the properties you want to modify:

@mixin color-transition($duration: 0.2s, $properties...) {
    $collector: ();

    // optional
    @if length($properties) == 0 {
        $properties: color, background-color, border-color;
    }

    @each $p in $properties {
        $collector: append($collector, $p $duration linear, comma);
    }

    transition: $collector;
}

Usage:

.foo {
  @include color-transition();
}

.bar {
  @include color-transition(0.2s, color);
}

.buzz {
  @include color-transition(0.2s, background-color, border-color);
}

Output:

.foo {
  transition: color 0.2s linear, background-color 0.2s linear, border-color 0.2s linear;
}

.bar {
  transition: color 0.2s linear;
}

.buzz {
  transition: background-color 0.2s linear, border-color 0.2s linear;
}

Variation to allow for optional duration:

@mixin color-transition($properties...) {
    // optional
    @if length($properties) == 0 {
        $properties: color, background-color, border-color;
    }

    $duration: 0.2s; // default value

    $collector: ();
    @each $p in $properties {
        @if type-of($p) == number {
            $duration: $p;
        } @else {
            $collector: append($collector, $p $duration linear, comma);
        }
    }

    transition: $collector;
}

.foo {
  @include color-transition(color);
}

As a quirky side-effect, you can specify different durations of each property:

.bar {
  @include color-transition(color, 0.3, background);
}

Upvotes: 1

Related Questions