XYZuser
XYZuser

Reputation: 21

How to create a 'transform' mixin in SCSS that uses several arguments?

I want to create a mixin for transform that has two arguments - translate and rotate. I've tried it in several ways but none of them works and I do not know why.

@mixin transform($transforms) {
    -moz-transform: $transforms;
    -o-transform: $transforms;
    -ms-transform: $transforms;
    -webkit-transform: $transforms;
    transform: $transforms;
}
@mixin rotate ($deg) {
    @include transform(rotate(#{$deg}deg));
}
@mixin translate($x, $y) {
    @include transform(translate($x, $y));
}

In nav.scss I included it like this

@include transform(rotate(45));
@include transform(translate(0,9px));

It doesn't change anything in the presentation page.

Without mixin I simply use:

span:before {
         transform: translateY(9px) rotate(45deg);
}

and it works but I want to achieve the same result with a mixin, but I don't know how. I started learning SASS a few days ago.

Upvotes: 2

Views: 2271

Answers (2)

Jakob E
Jakob E

Reputation: 4926

In general, I would recommend you use Autoprefixer to handle vendor prefixes as you'll often add way more prefixes than needed.

In the case of transform, you would probably be fine just adding

-webkit-transform: ...;
        transform: ...;

Also, it becomes rather hard to handle when you need to deal with property values:

  transition: transform 300ms;

  // prefixed  
  -webkit-transition: -webkit-transform 300ms;
          transition: -webkit-transform 300ms;
          transition: transform 300ms;
          transition: transform 300ms, -webkit-transform 300ms;

To answer your question I think the easiest way is to use argument-lists (allows any number of arguments to be passed) joined together in a space-separated list:

// Mixin 
@mixin transform($transforms...) {
    // combine the passed transforms into a space separated list
    $transform-list: join($transforms, null, space);

    // print out the transforms 
    -webkit-transform: $transform-list;
       -moz-transform: $transform-list;
        -ms-transform: $transform-list;
         -o-transform: $transform-list;
            transform: $transform-list;
}


// Include 
span::before {
    @include transform(
        rotate(90deg),
        translate(0,9px),
        // ... add more transforms if you need
    );
}


// CSS output 
span::before {
    -webkit-transform: rotate(90deg) translate(0, 9px);
       -moz-transform: rotate(90deg) translate(0, 9px);
        -ms-transform: rotate(90deg) translate(0, 9px);
         -o-transform: rotate(90deg) translate(0, 9px);
            transform: rotate(90deg) translate(0, 9px);
}

Upvotes: 3

Gh05d
Gh05d

Reputation: 8962

I don't think that you need to nest the mixins like that. You can take advantage of optional arguments and the keyword syntax:

@mixin transformNew($rotate: 0, $translate: translate(0, 0)) {
  -moz-transform: rotate(#{$rotate}deg) $translate;
    -o-transform: rotate($rotate) $translate;
    -ms-transform: rotate(#{$rotate}deg) $translate;
    -webkit-transform: rotate(#{$rotate}deg) $translate;
    transform: rotate(#{$rotate}deg) $translate;
}

div {
  @include transformNew($translate: translate(10px, 40px));
  background: red;
}

The arguments for the mixin now have a default value, if you want to call it with only one argument. You can call arguments explicitly by using the keyword syntax. In my example I wanted only the second argument, so I did this: @include transformNew($translate: translate(10px, 40px));. If you only need the first argument, then it is enough to just pass the value, no need for the keyword.

If you need both arguments, you can simply pass them both. In your code, if you called the mixin twice, you had overwritten the first value with the second call. That won't happen here. I also created a codepen for you to play around with the code.

Upvotes: 0

Related Questions