how to write Less mixin for keyframes.
I have tried in the following way but it is giving error,
ParseError: Directive options not recognized.
.keyFrameAlert(#-webkit-keyframes);
Mixin
.keyFrameAlert(#keyFrame){
#keyFrame alert {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
top: 0;
}
}
}
can anybody help on this issue.
I think it might be throwing an error because of the # prefix for your keyframes, so where your passing #-webkit-keyframes it thinks your trying to pass it a variable with that same name.
There is a slightly different approach to this, where you can declare your keyframes, and add a class inside it which contains your keyframe set.
#-webkit-keyframes alert {.keyframes;}
#keyframes alert {.keyframes;}
.keyframes () {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
top: 0;
}
}
This is slightly different to what you were trying previously, as you would still need to type out all of your vendor prefixes, but you only need to change your keyframes in one place.
While validating for CSS3, following error can be seen for my Website:
Sorry, the at-rule #-moz-keyframes is not implemented
Below is the CSS code:
Line 16:
#-moz-keyframes spin {
0% {
-moz-transform:rotate(0deg)
}
100% {
-moz-transform:rotate(359deg)
}
}
#-webkit-keyframes spin {
0% {
-webkit-transform:rotate(0deg)
}
100% {
-webkit-transform:rotate(359deg)
}
}
#-ms-keyframes spin {
0% {
-ms-transform:rotate(0deg)
}
100% {
-ms-transform:rotate(359deg)
}
}
#keyframes spin {
0% {
transform:rotate(0deg)
}
100% {
transform:rotate(359deg)
}
}
.fa-rotate-90 {
filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
-webkit-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-ms-transform:rotate(90deg);
transform:rotate(90deg)
}
I would like to know what kind of CSS validation Error is this and what can be the better solution for this error
According to caniuse, the -moz-animation (and corresponding #-moz-keyframes) was used by Firefox 5-15.
Most likely the validator you're using assumes (rightly) that effectively all serious users (at least 99.65% of Firefox users, even less in the total scope of things) will be using a more modern Firefox than Firefox 15.
As a result, it's pretty safe to leave it out if you're want to remove the "error".
I'm trying to workaround Bourbon not supporting #keyframe by generating my own prefixes version with a Sass loop like this:
$list: '' -ms- -webkit- -moz- -o-
$at: # //at sign
#each $prefix in $list
#{$at}#{$prefix}keyframes moveclouds
from
#{$prefix}transform: translateX(2400px)
to
#{$prefix}transform: translateX(-400px)
and expecting to generate css:
#keyframes moveclouds from {
transform: translateX(2400px);
}
#keyframes moveclouds to {
transform: translateX(-400px);
}
#-moz-keyframes moveclouds from {
-moz-transform: translateX(2400px);
}
#-moz-keyframes moveclouds to {
-moz-transform: translateX(-400px);
}
....
the issue is that I cannot figure out how to force Sass output # (at sign) in start of a line
if I do
$at: # // wont work, error
$at: \# // will generate \#keyframes = not good
$at: "\#" // wont work error
$at: ## // will generate ##keyframes = not good
so anyone got an idea how to output at sign in Sass ?
This simply isn't possible using variable interpolation. You can get around the # assignment like this:
$at: unquote("#"); // either of these will work
$amp: #{"#"};
But then you end up with this error:
error sass/test.scss (Line 4: Invalid CSS after "": expected selector_comma_sequence, was "#-ms-keyframes ...")
Interpolation on #keyframes is not currently supported, but will be in the future. You can track the progress of that on GitHub. In the mean time, you'll have to write out your keyframe information by hand. A simple example looks like this:
#mixin keyframes($name) {
#-webkit-keyframes #{$name} {
#content;
}
#keyframes #{$name} {
#content;
}
}
Usage:
#include keyframes(foo) {
0% {
color: red;
}
100% {
color: blue;
}
}
A more complex example can be found in Eric Meyer's Sass Animation library.
So, it is possible to have reverse animation on mouse out such as:
.class{
transform: rotate(0deg);
}
.class:hover{
transform: rotate(360deg);
}
but, when using #keyframes animation, I couldn't get it to work, e.g:
.class{
animation-name: out;
animation-duration:2s;
}
.class:hover{
animation-name: in;
animation-duration:5s;
animation-iteration-count:infinite;
}
#keyframe in{
to {transform: rotate(360deg);}
}
#keyframe out{
to {transform: rotate(0deg);}
}
What is the optimal solution, knowing that I'd need iterations and animation itself?
http://jsfiddle.net/khalednabil/eWzBm/
I think that if you have a to, you must use a from.
I would think of something like :
#keyframe in {
from: transform: rotate(0deg);
to: transform: rotate(360deg);
}
#keyframe out {
from: transform: rotate(360deg);
to: transform: rotate(0deg);
}
Of course must have checked it already, but I found strange that you only use the transform property since CSS3 is not fully implemented everywhere. Maybe it would work better with the following considerations :
Chrome uses #-webkit-keyframes, no particuliar version needed
Safari uses #-webkit-keyframes since version 5+
Firefox uses #keyframes since version 16 (v5-15 used #-moz-keyframes)
Opera uses #-webkit-keyframes version 15-22 (only v12 used #-o-keyframes)
Internet Explorer uses #keyframes since version 10+
EDIT :
I came up with that fiddle :
http://jsfiddle.net/JjHNG/35/
Using minimal code. Is it approaching what you were expecting ?
Its much easier than all this: Simply transition the same property on your element
.earth { width: 0.92%; transition: width 1s; }
.earth:hover { width: 50%; transition: width 1s; }
https://codepen.io/lafland/pen/MoEaoG
I don't think this is achievable using only CSS animations. I am assuming that CSS transitions do not fulfil your use case, because (for example) you want to chain two animations together, use multiple stops, iterations, or in some other way exploit the additional power animations grant you.
I've not found any way to trigger a CSS animation specifically on mouse-out without using JavaScript to attach "over" and "out" classes. Although you can use the base CSS declaration trigger an animation when the :hover ends, that same animation will then run on page load. Using "over" and "out" classes you can split the definition into the base (load) declaration and the two animation-trigger declarations.
The CSS for this solution would be:
.class {
/* base element declaration */
}
.class.out {
animation-name: out;
animation-duration:2s;
}
.class.over {
animation-name: in;
animation-duration:5s;
animation-iteration-count:infinite;
}
#keyframes in {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#keyframes out {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
And using JavaScript (jQuery syntax) to bind the classes to the events:
$(".class").hover(
function () {
$(this).removeClass('out').addClass('over');
},
function () {
$(this).removeClass('over').addClass('out');
}
);
Creating a reversed animation is kind of overkill to a simple problem. What you need is:
animation-direction: reverse
However, this won't work on its own because animation spec forgot to add a way to restart the animation, so here is how you do it with the help of JS
let item = document.querySelector('.item')
// play normal
item.addEventListener('mouseover', () => {
item.classList.add('active')
})
// play in reverse
item.addEventListener('mouseout', () => {
item.style.opacity = 0 // avoid showing the init style while switching the 'active' class
item.classList.add('in-active')
item.classList.remove('active')
// force dom update
setTimeout(() => {
item.classList.add('active')
item.style.opacity = ''
}, 5)
item.addEventListener('animationend', onanimationend)
})
function onanimationend() {
item.classList.remove('active', 'in-active')
item.removeEventListener('animationend', onanimationend)
}
#keyframes spin {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(180deg);
}
}
div {
background: black;
padding: 1rem;
display: inline-block;
}
.item {
/* because span cant be animated */
display: block;
color: yellow;
font-size: 2rem;
}
.item.active {
animation: spin 1s forwards;
animation-timing-function: ease-in-out;
}
.item.in-active {
animation-direction: reverse;
}
<div>
<span class="item">ABC</span>
</div>
we can use requestAnimationFrame to reset animation and reverse it when browser paints in next frame.
Also use onmouseenter and onmouseout event handlers to reverse animation direction
As per
Any rAFs queued in your event handlers will be executed in the same
frame. Any rAFs queued in a rAF will be executed in the next frame.
function fn(el, isEnter) {
el.className = "";
requestAnimationFrame(() => {
requestAnimationFrame(() => {
el.className = isEnter? "in": "out";
});
});
}
.in{
animation: k 1s forwards;
}
.out{
animation: k 1s forwards;
animation-direction: reverse;
}
#keyframes k
{
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
<div style="width:100px; height:100px; background-color:red"
onmouseenter="fn(this, true)"
onmouseleave="fn(this, false)"
></div>
Would you be better off having just the one animation, but having it reverse?
animation-direction: reverse
Using transform in combination with transition works flawlessly for me:
.ani-grow {
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
-ms-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.ani-grow:hover {
transform: scale(1.01);
}
I've put together a CodePen with a CSS-only fix and one with 2 lines of jQuery to fix the on-page load issue. Continue reading to understand the 2 solutions in a simpler version.
https://codepen.io/MateoStabio/pen/jOVvwrM
If you are searching how to do this with CSS only, Xaltar's answer is simple, straightforward, and is the correct solution. The only downside is that the animation for the mouse out will play when the page loads. This happens because to make this work, you style your element with the OUT animation and the :hover with the IN animation.
svg path{
animation: animateLogoOut 1s;
}
svg:hover path{
animation: animateLogoIn 1s;
}
#keyframes animateLogoIn {
from {stroke-dashoffset: -510px;}
to {stroke-dashoffset: 0px;}
}
#keyframes animateLogoOut {
from {stroke-dashoffset: 0px;}
to {stroke-dashoffset: -510px;}
}
Some people found this solution to be useless as it played on page load. For me, this was the perfect solution. But I made a Codepen with both solutions as I will probably need them in the near future.
If you do not want the CSS animation on page load, you will need to use a tiny little script of JS that styles the element with the OUT animation only after the element has been hovered for the first time. We will do this by adding a class of .wasHovered to the element and style the added class with the OUT Animation.
jQuery:
$("svg").mouseout(function() {
$(this).addClass("wasHovered");
});
CSS:
svg path{
}
svg.wasHovered path{
animation: animateLogoOut 1s;
}
svg:hover path{
animation: animateLogoIn 1s;
}
#keyframes animateLogoIn {
from {stroke-dashoffset: -510px;}
to {stroke-dashoffset: 0px;}
}
#keyframes animateLogoOut {
from {stroke-dashoffset: 0px;}
to {stroke-dashoffset: -510px;}
}
And voila! You can find all of this and more on my codepen showing in detail the 2 options with an SVG logo hover animation.
https://codepen.io/MateoStabio/pen/jOVvwrM
Have tried several solutions here, nothing worked flawlessly; then Searched the web a bit more, to find GSAP at https://greensock.com/ (subject to license, but it's pretty permissive); once you reference the lib ...
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js"></script>
... you can go:
var el = document.getElementById('divID');
// create a timeline for this element in paused state
var tl = new TimelineMax({paused: true});
// create your tween of the timeline in a variable
tl
.set(el,{willChange:"transform"})
.to(el, 1, {transform:"rotate(60deg)", ease:Power1.easeInOut});
// store the tween timeline in the javascript DOM node
el.animation = tl;
//create the event handler
$(el).on("mouseenter",function(){
//this.style.willChange = 'transform';
this.animation.play();
}).on("mouseleave",function(){
//this.style.willChange = 'auto';
this.animation.reverse();
});
And it will work flawlessly.
Try this:
#keyframe in {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#keyframe out {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
supported in Firefox 5+, IE 10+, Chrome, Safari 4+, Opera 12+
I have realized that I can't simple accomplish the same code below by separating by coma #keyframes mymove, #-moz-keyframes mymove, etc... In order for them to work I need to declare it each one separately as below.
Is there any way to group them and make this code shorter?
#keyframes mymove
{
from {top:0px;}
to {top:200px;}
}
#-moz-keyframes mymove /* Firefox */
{
from {top:0px;}
to {top:200px;}
}
#-webkit-keyframes mymove /* Safari and Chrome */
{
from {top:0px;}
to {top:200px;}
}
no, I don't think so, but you could use a CSS language (aka CSS preprocessor) like SASS/SCSS/LESS/... - the output (CSS) would still be the same, but changing something would be much easier!
Check out
http://sass-lang.com/
http://coding.smashingmagazine.com/2011/09/09/an-introduction-to-less-and-comparison-to-sass/
if you're interested - the effort of installing them and setting them up is totally worth it!
EDIT: Using SCSS I did the following:
#mixin keyframes($name) {
#-webkit-keyframes #{$name} { #content; }
#-moz-keyframes #{$name} { #content; }
#keyframes #{$name} { #content; }
}
example of usage:
#include keyframes(pulse) {
0%,100% {
opacity: 0;
}
50% {
opacity: 1;
}
}
Although it should be added that you need the latest pre-release of SASS to be able to nest rules (we have got a "{" inside another "{" rule...) so you should update run "gem install sass --pre" which should get you "sass-3.2.0.alpha.104"