28

I try to set up this LESS mixin for CSS animation keyframes:

.keyframes(@name, @from, @to) {;
  @-webkit-keyframes "@name" {
    from {
      @from;  
    }
    to {
      @to;
    }
  }
}

but there is some problem with name pharse, is there any option to do this corectly?

Lukas
  • 7,384
  • 20
  • 72
  • 127
  • possible duplicate of [@ sign and variables in CSS keyframes using LESS CSS](http://stackoverflow.com/questions/9166152/sign-and-variables-in-css-keyframes-using-less-css) — Although the highest voted answer here is currently more up-to-date than the top answer in the other question. – Jari Keinänen May 06 '15 at 07:07
  • try this code https://css-tricks.com/forums/topic/keyframes-is-not-working-in-less-mixin-with-lesshat/ – Haydar C. Jan 05 '16 at 13:35
  • after 2 years, thanks :) – Lukas Jan 08 '16 at 10:24

6 Answers6

32

As of LESS >= 1.7 you can use variables for keyframe keywords (names).

Some changes have been made in LESS 1.7 to how directives work, which allows to use variables for the name/keyword of @keyframes (so the example from the question should work now).


Unfortunately keyframes names can not be dynamically generated in LESS <= 1.6

Hence, the normal way of going about keyframes would use hardcoded names and you would only call for specific "for" and "to" mixins, like this:

.colors-mixin-frame(@from,@to){
from {color: @from;}
to {color: @to;}
}

.width-mixin-frame(@from,@to){
from {width: @from;}
to {width: @to;}
}

// keyframes with hardcoded names calling for specific mixin frames
@keyframes red-blue { .colors-mixin-frame(red, blue); }
@keyframes change-width { .width-mixin-frame(254px, 512px); }

But you can use a workaround to dynamically generate the names

where you inject the name into the rule name, this however requires an declaration of the next rule that supplies the closing bracket } at the end of the keyframes declaration. The most convenient is if you just build the animation calling that keyframe

.animation-keyframes(@name, @from, @to, @anim-selector) {
  @keyf: ~"@keyframes @{name} { `'\n'`from ";
  @anim: ~"} `'\n'`.@{anim-selector}";
  @{keyf} {
      .from(@name,@from);
        }
      to {
        .to(@name,@to);
      }
  @{anim} {
    animation-name:@name;
  }
}

Note that you also need to define .from(){} and .to(){} mixins, and not just use @from and @to like you did in your example (because LESS also does not allow for dynamically generated properties) ... this mixins can now construct the desired properties and values ... to use specific property you can use guards or name-specific mixins like these:

// name-specific from and to mixins that are used if first argument equals "colors"
.from (colors, @color) {
  color: @color;
}
.to (colors, @color) {
  color: @color;
} 

Now we can call our mixin in LESS:

// test
.animation-keyframes (colors, red, blue, my-colanim);

and get CSS:

@keyframes colors { 
from {
  color: #ff0000;
}
to {
  color: #0000ff;
}
} 
.my-colanim {
  animation-name: colors;
}

this will work also in LESS 1.4, but note that we used javascript interpolation for line breaks, which requires a javascript implementation of LESS.


Edit: to your additional question about prefixes

Mixin with vendor prefixes

Here I made two mixins ... one without vendor prefixes and one with them both calling a general .keyframes mixin:

.keyframes (@name, @from, @to, @vendor:"", @bind:"") {
  @keyf: ~"@{bind}@@{vendor}keyframes @{name} { `'\n'`from ";
  @{keyf} {
      .from(@name,@from);
        }
      to {
        .to(@name,@to);
      }
}

.animation-keyframes-novendor (@name, @from, @to, @anim-selector) {
  .keyframes (@name, @from, @to);
  @anim: ~"} `'\n'`.@{anim-selector}";
  @{anim} {
    animation-name:@name;
  }
}

.animation-keyframes (@name, @from, @to, @anim-selector) {
  @bind: "} `'\n'`";
  .keyframes (@name, @from, @to, "-moz-");
  .keyframes (@name, @from, @to, "-webkit-", @bind);
  .keyframes (@name, @from, @to, "-o-", @bind);
  .keyframes (@name, @from, @to, "-ms-", @bind);
  .keyframes (@name, @from, @to, "", @bind);
  @anim: ~"} `'\n'`.@{anim-selector}";
  @{anim} {
    -moz-animation: @name;
    -webkit-animation: @name;
    -o-animation: @name;
    -ms-animation: @name;
    animation: @name;
  }
}

.from (colors, @color) {
  color: @color;
}
.to (colors, @color) {
  color: @color;
}

/* keyframes with all vendor prefixes */
.animation-keyframes (colors, red, blue, my-colanim);

/* keyframes with no vendor prefix */
.animation-keyframes-novendor (colors, red, blue, my-colanim);

The .animation-keyframes will now produce keyframes for all vendor prefixes and an animation selector with vendor prefixed properties. And as expected the .animation-keyframes-novendor gives the same output as the above simple solution (without vendor prefixes).


Some notes:

  • For your animation to actually work you need to set other animation parameters like timing-function, duration, direction, iteration-count (requires at least a duration time in addition to the name that we already set).

    For example:

   animation: @name ease-in-out 2s infinite alternate;
  • If you wrap above mixins in namespaces make sure you change the mixin references inside other mixins to their whole path (including the namespaces).

    For example:

   #namespace > .keyframes () // see .less source in the demo for details
Community
  • 1
  • 1
Martin Turjak
  • 20,896
  • 5
  • 56
  • 76
  • much thx for this, this looks promising and i will check it soon – Lukas Apr 23 '13 at 09:03
  • i have one question, what with prefixes? – Lukas May 02 '13 at 09:19
  • 1
    @djlukas777 I added an extended version of the mixin for vendor prefixes to the answer. – Martin Turjak May 02 '13 at 10:20
  • Yesterday I came back to get this code to generate some vendor keyframes to [answer another question](http://stackoverflow.com/questions/16528777/how-to-fetch-the-background-of-div-on-a-bottom-layer-with-exact-position-using-j/16575762#16575762), and I saw that you haven't replied or accepted my answer ... did you not like something in the solution? Would you wan't me to elaborate anything further? Anyway, hope it worked for you at the end =) – Martin Turjak May 16 '13 at 22:30
  • I'm sorry for the lack of feedback. So - i tried, but my IDE crashes LESS syntax error I do not know why that is, I tried to follow all the commas and semicolons, but everything seems to be OK – Lukas May 17 '13 at 08:20
  • it might be due to the javascript interpolation if you don't use a javascript implementation of LESS or LESS <=1.3.0 - try taking out all occurrences of `\`'\n'\`` ... this is not necessary ... it just tidies up the output a tiny bit. Hope it helps ^_^ – Martin Turjak May 17 '13 at 08:29
  • Martin, could you explain how to use these in LESS markup? I've got these in my mixins.less but I'm unsure how to create the animation keyframes & apply the animation to an element. – chandlervdw Sep 19 '13 at 15:38
  • @chandlervdw Hi! In the example above I focused on the LESS part - to get the desired CSS output with dynamically assigning names. The CSS only has the animation name and you should adjust it to your needs (a working animation in CSS requires at least a duration time in addition) ... you should actually add some animation parameters, like the timing-function, duration, direction, iteration-count. Here is a working example in [**jsfiddle**](http://jsfiddle.net/KZfd7/21/). – Martin Turjak Sep 19 '13 at 17:53
  • 1
    This solution worked for me. I was not able to use this mixin from within a namespace. So if you are putting the mixin, for example, within the ``#animation`` namespace, and you call it with ``#animation > .animation-keyframes(...)``, you will get a message saying that the mixin is not defined. Does anyone know of a way to work around this while still working from within the namespace? – user1429980 Nov 27 '13 at 05:54
  • 1
    @user1429980 if you wrap above mixins in a namespace it should work, you just should make sure that you call all the mixins (also from inside other mixins in the namespace) with their whole path (including the namespace e.g. `#animation > .keyframes(...)` inside `.animation-keyframes(...)` mixin). [**DEMO**](http://newtpond.com/test/less-keyframes.html) – Martin Turjak Nov 27 '13 at 10:06
  • @MartinTurjak, I've been trying to refactor this mixin to no avail; I do not want the extended ``animation`` rules appended to the ``@keyframes`` for each vendor. So my result is that the last left curly brace is omitted, as I remove the ``anim-selector``, and since it's not used, less does not output the ``@anim`` variable, which uses the escaped ``~"} `'\n'`"``. Ideas?? – user1429980 Dec 24 '13 at 05:26
  • @MartinTurjak, thanks for this great answer, One question though: How do I reuse this mixin? I made this codepen http://codepen.io/danield770/pen/uBxiF - where I want to reuse the same color-change animation on two separate divs - but with different animation properties like duration etc. – Danield Jan 29 '14 at 10:51
  • 1
    @Danield if you want to reuse the same `.from` and `.to` mixins you need to hardcode it in the `.keyframes` mixin (or add another parameter, depends on what you want to do with it), as the generated keyframes with different properties need different names now (e.g: `color-change2`, but the steps that you want to use should keep `color-change`) ... here I forked your pen with the updated `.keyframes` mixin: [**codepen example**](http://codepen.io/mturjak/pen/wlicI) – Martin Turjak Jan 29 '14 at 11:27
  • @Danield bevakasha, bevakasha! ;-) I created [**a chat room for any followup questions/discussion**](http://chat.stackoverflow.com/rooms/46337/how-to-set-keyframes-names-in-less), as I think this comments were getting quite long. – Martin Turjak Jan 29 '14 at 12:33
  • In the version 1.7.0 they are mentioning something about @keyframes.. Is it solved now maybe? https://github.com/less/less.js/blob/master/CHANGELOG.md#170 – Lipis Mar 01 '14 at 22:33
  • @Lipis yes, you can do the part from the original question now (using a variable as the keyframes name) [DAMO](http://newtpond.com/test/less-1-7/). As to the additional question (for vendor prefixes), you still need to wiggle a bit to get Less spit out nicely prefixed keyframes. – Martin Turjak Mar 02 '14 at 17:05
6

I am currently working on a mixin library

The source can be found here https://github.com/pixelass/more-or-less

My keyframe mixin looks like this:

WORKS FOR LESS 1.7.x

MIXIN

.keyframes(@name) { 
    @-webkit-keyframes @name {
        .-frames(-webkit-);
    }
    @-moz-keyframes @name {
        .-frames(-moz-);
    }
    @keyframes @name {
        .-frames();
    }
}

INPUT

& {
    .keyframes(testanimation);.-frames(@-...){
        0% {
            left: 0;
            @{-}transform: translate(10px, 20px);
        }

        100% {
            left: 100%;
            @{-}transform: translate(100px, 200px);
        }
    }
}

OUTPUT

@-webkit-keyframes testanimation {
  0% {
    left: 0;
    -webkit-transform: translate(10px, 20px);
  }
  100% {
    left: 100%;
    -webkit-transform: translate(100px, 200px);
  }
}
@-moz-keyframes testanimation {
  0% {
    left: 0;
    -moz-transform: translate(10px, 20px);
  }
  100% {
    left: 100%;
    -moz-transform: translate(100px, 200px);
  }
}
@keyframes testanimation {
  0% {
    left: 0;
    transform: translate(10px, 20px);
  }
  100% {
    left: 100%;
    transform: translate(100px, 200px);
  }
}
2

How about this:

@-webkit-keyframes some-animation {.mixi-frames;}
@-moz-keyframes some-animation {.mixi-frames;}
@-ms-keyframes some-animation {.mixi-frames;}
@-o-keyframes some-animation {.mixi-frames;}
@keyframes some-animation {.mixi-frames;}

.mixi-frames () {
    from {width: 254px;}
    to {width: 512px;}
}

You need to do it for each animation. Taken from: http://radiatingstar.com/css-keyframes-animations-with-less

JVitela
  • 2,472
  • 2
  • 22
  • 20
1

Also thanks to the great answer by Martin Turjak, (thank you for that) I just put on github a less mixin which generate keyframes and animation's css code without hacks and in a flexible way, you can find it here github.com/kuus/animate-me.less.

With this mixin you can write this code to obtain valid and cross browser css (see the github repo for a complete explanation):

.animate-me(ComplexAnimation; 0.4s ease; '.complex-animation';
    '50%, 100%'; '%stransform: translateZ(-250px) rotateY(30deg)';
    70%; '%stransform: translateZ(-250px) rotateY(30deg); opacity: .5; background:   green';
    30%; '%stransform: translateZ(-250px) rotateY(30deg); opacity: .2; background: yellow';
    80%; '%stransform: translateZ(-250px) rotateY(30deg); opacity: 1; background: red'
);
Community
  • 1
  • 1
kuus
  • 453
  • 1
  • 5
  • 15
0

I think you should do this

@-webkit-keyframes @name 
{
 code...
}

change "@name" to @name

and you should delete ; after

.keyframes(@name, @from, @to) {
Martin Turjak
  • 20,896
  • 5
  • 56
  • 76
tcgumus
  • 328
  • 3
  • 8
0

Before-mentioned https://github.com/kuus/animate-me.less does things!

You can also check out this one written by me (seems to be neater): https://github.com/thybzi/keyframes

thybzi
  • 1,223
  • 13
  • 15