Search code examples
csssass

construct single CSS rule with @each


I am looking for a way to construct a single CSS rule using severals parameters with Sass.

Let's say I want to create a mixin transition that takes targets as parameters to write one transition CSS rule (other parameters like transition time, etc. are constant).

@mixin transition($targets...) {
    @each $t in $targets {
        // construct the rule target by target
    }
    // and then transition: $rule; or something similar
}

I want to call it like

.foo {
    @include transition(color, width);
}

and get

.foo {
    transition: color 100ms ease-out, width 100ms ease-out;
}

Problem is, I was not able to find a way to construct a string by concatenation. Is it even possible, or is there a different way to do this?


Solution

  • Here's one way:

    @mixin transition($targets...) {
        $items: "";
        @each $item in $targets {
            $i: index($targets, $item);
            @if $i == length($targets) {
              $items: $items + $item + " 100ms ease-out";
            }
    
            @else {
              $items: $items + $item + " 100ms ease-out, ";
            }
        }
        transition: unquote($items);
    }
    

    Codepen (see compiled css)

    1) Set a variable to hold the string

    $items: "";

    2) In the $each loop iteration get the index:

    $i: index($targets, $item);
    

    3) Concatenate each item to the $items variable. If it's the last item - then the string won't end with a comma - otherwise it will

    @if $i == length($targets) {
      $items: $items + $item + " 100ms ease-out";
    }
    
    @else {
      $items: $items + $item + " 100ms ease-out, ";
    }
    

    4) Finally remove the quotes from the string with unquote

    transition: unquote($items);
    

    Usage:

    .foo {
        @include transition(color, width);
    }
    

    Which produces compiled CSS:

    .foo {
      transition: color 100ms ease-out, width 100ms ease-out;
    }