Javascript degradation solutions for CSS3 animations - javascript
I've been creating a number of small thick client JavaScript apps for an iPad app, which loads the relevant app in a UIWebview. I am now making them cross browser and need to incorporate some fallbacks for CSS animations and transitions using JavaScript.
My webkit specific implementation uses CSS classes for all animations/transitions, for which the start and end states are known at design time, using add/remove class in javascript and utilising the relevant webkitTransitionEnd/webkitAnimationEnd events.
For 'dynamic' transitions I have a simple 'animate' function which just applies styling properties to relevant elements.
I would like to keep the internal API for appling transitions as similar as possible to the current implementation by simple adding/removing classes etc. I generally have a CSS and js file (both minified) for an app.
So a few questions/points that I would appreciate any input on:
IE7/8 issues - IE9.js
Dynamically adding vendor specific prefixes - so far found 'jquery.css3finalize'.
Transitioning to a class: 'jquery.animateToClass' - seems to search stylesheet(s) every time a class is applied - should relevant classes be cached on further lookups? Is this slow/resource hungry?
For '#keyframe' animations: I'd like to have a javascript object 'representation' of keyframes of each CSS3 animation. Therefore passing a class to the 'doAnimationWithClass' function would use normal css3 animation if available in the browser but if not it would pass the 'object version' to a function that would chain the each key frame transition using css3 transitions (if available) or jQuery.animate (or equivalent), ultimately arriving at the same result.
So for instance:
CSS:
#-webkit-keyframes an-animation {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
.an-animation {
-webkit-animation-name: an-animation;
-webkit-animation-duration: 1s;
-webkit-animation-timing-function: linear;
-webkit-animation-iteration-count: 2;
}
JS:
var animations = {
an-animation: {
keyframes: [
{
duration: '',
timing: 'linear',
props: {
opacity: 0
}
},
{
duration: '0.5s',
timing: 'linear',
props: {
opacity: 1
}
},
{
duration: '0.5s',
timing: 'linear',
props: {
opacity: 0
}
}
]
}
};
var animationClasses = [
an-animation: {
name: 'an-animation';
duration: '1s';
timing: 'linear';
count: 2;
}
];
function doAnimationWithClass(className) {
if (modernizer.cssanimations) {
//normal implementation
}
else {
//lookup class in animationclasses
//lookup relevant animation object in animationHash
//pass to animation chaining function
}
}
The creation of animationHash etc could be done client side, or simply created at design time (with a batch/build file).
Any thoughts or pointers to a library that already does this in a more sensible way would be appreciated.
Yes, that's right. You need to transfer keyframes setting to js object. I think css animation and keyframe is a better way to write animation. JS animation way is hardly to maintain. Here is my workaround solution. And I also write a small tool for translating css keyframes to js object(css keyframes to js object) .
var myFrame = {
'0%': {
left: 0,
top: 0
},
'25%': {
left: 100,
top: 100
},
'50%': {
left: 0,
top: 300
},
'100%': {
left: 0,
top: 0
}
};
var keyframes = {
set: function($el, frames, duration) {
var animate;
animate = function() {
var spendTime;
spendTime = 0;
$.each(frames, function(idx, val) {
var stepDuration, stepPercentage;
stepPercentage = idx.replace('%', '') / 100;
stepDuration = duration * stepPercentage - spendTime;
$el.animate(val, stepDuration);
return spendTime += stepDuration;
});
return setTimeout(animate, duration);
};
return animate();
}
};
keyframes.set($('#mydiv'), myFrame, 2000);
demo: http://jsbin.com/uzodut/4/watch
Here are some important pointers http://addyosmani.com/blog/css3transitions-jquery/
Blackbingo, you answer served to me perfectly. I added the easing option, to implement a jquery fallback for ie8 in a parallax starfield (see CSS parallax background of stars) like this:
var animations = {
'STAR-MOVE': {
'0%': {
'background-position-x': '5%',
'background-position-y': '5%'
},
'100%': {
'background-position-x': '1300%',
'background-position-y': '600%'
}
}
};
var keyframes = {
set: function($el, frames, duration, easing) {
var animate;
animate = function() {
var spendTime;
spendTime = 0;
$.each(frames, function(idx, val) {
var stepDuration, stepPercentage;
stepPercentage = idx.replace('%', '') / 100;
stepDuration = duration * stepPercentage - spendTime;
$el.animate(val, stepDuration, easing);
return spendTime += stepDuration;
});
return setTimeout(animate, duration);
};
return animate();
}
};
keyframes.set($('.midground'), animations['STAR-MOVE'], 150000,'linear');
keyframes.set($('.foreground'), animations['STAR-MOVE'], 100000,'linear');
Related
easing speed of blink for text in a jackpot game
I am making a jackpot game with a selector very similar to this one I have absolutely no idea where to start. My first thought was to use an array of randomly selected numbers sent from the server side to avoid cheating and animate those with jquery or css. Then i thought about useing just jquery since i know it better and having the blink interval be a recursive fucnction that returns the values for easing speed i want. (the values would be pretty much exactly like in the video, no more than 3-4 seconds). $('.blink').blink(); // default is 500ms blink interval. $('.blink').blink(100); // causes a 100ms blink interval. But now I am at a loss for where to get started since this has to be mobile friendly. What would you do? UPDATE $( document ).ready(function() { var time = 0; var diff = 50; var minTime = 0; var maxTime = 7000; function easeInOutExpo(t, b, c, d) { t /= d; return c*t*t*t + b; }; $("#clickme").click(function() { for (var i = 0, len = diff; i <= len; i++) { (function(s) { setTimeout(function() { $('#book').html("Page " + s + " turned"); }, time); })(i); //<--------------i have no clue what this does------------ time = easeInOutExpo(i, minTime, maxTime, diff); } }); });//document ready I've gotten the basic mechanic down, but when you click on it a second time instead of 50 it goes to 0. this is not good behavior as I am going to use these numbers to iterate through a randomly generated array. Can anyone explain this behaviour? I've included a JS fiddle here. Thank you!
You can use simple css animation. #keyframes blink { 0% { background-color:red; } 10% { background-color:purple; } 20% { background-color:gray; } 30% { background-color:green; } 40% { background-color:white; } 50% { background-color:cyan; } 65% { background-color:yellow; } 100% { background-color:black } } .Blink{ animation: blink 2s 1 ease-out; background-color:black; height:100px; width:100px; } <div class="Blink">
Flashing text on value change [duplicate]
I'm brand new to jQuery and have some experience using Prototype. In Prototype, there is a method to "flash" an element — ie. briefly highlight it in another color and have it fade back to normal so that the user's eye is drawn to it. Is there such a method in jQuery? I see fadeIn, fadeOut, and animate, but I don't see anything like "flash". Perhaps one of these three can be used with appropriate inputs?
My way is .fadein, .fadeout .fadein, .fadeout ...... $("#someElement").fadeOut(100).fadeIn(100).fadeOut(100).fadeIn(100); function go1() { $("#demo1").fadeOut(100).fadeIn(100).fadeOut(100).fadeIn(100)} function go2() { $('#demo2').delay(100).fadeOut().fadeIn('slow') } #demo1, #demo2 { text-align: center; font-family: Helvetica; background: IndianRed; height: 50px; line-height: 50px; width: 150px; } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <button onclick="go1()">Click Me</button> <div id='demo1'>My Element</div> <br> <button onclick="go2()">Click Me</button> (from comment) <div id='demo2'>My Element</div>
You can use the jQuery Color plugin. For example, to draw attention to all the divs on your page, you could use the following code: $("div").stop().css("background-color", "#FFFF9C") .animate({ backgroundColor: "#FFFFFF"}, 1500); Edit - New and improved The following uses the same technique as above, but it has the added benefits of: parameterized highlight color and duration retaining original background color, instead of assuming that it is white being an extension of jQuery, so you can use it on any object Extend the jQuery Object: var notLocked = true; $.fn.animateHighlight = function(highlightColor, duration) { var highlightBg = highlightColor || "#FFFF9C"; var animateMs = duration || 1500; var originalBg = this.css("backgroundColor"); if (notLocked) { notLocked = false; this.stop().css("background-color", highlightBg) .animate({backgroundColor: originalBg}, animateMs); setTimeout( function() { notLocked = true; }, animateMs); } }; Usage example: $("div").animateHighlight("#dd0000", 1000);
You can use css3 animations to flash an element .flash { -moz-animation: flash 1s ease-out; -moz-animation-iteration-count: 1; -webkit-animation: flash 1s ease-out; -webkit-animation-iteration-count: 1; -ms-animation: flash 1s ease-out; -ms-animation-iteration-count: 1; } #keyframes flash { 0% { background-color: transparent; } 50% { background-color: #fbf8b2; } 100% { background-color: transparent; } } #-webkit-keyframes flash { 0% { background-color: transparent; } 50% { background-color: #fbf8b2; } 100% { background-color: transparent; } } #-moz-keyframes flash { 0% { background-color: transparent; } 50% { background-color: #fbf8b2; } 100% { background-color: transparent; } } #-ms-keyframes flash { 0% { background-color: transparent; } 50% { background-color: #fbf8b2; } 100% { background-color: transparent; } } And you jQuery to add the class jQuery(selector).addClass("flash");
After 5 years... (And no additional plugin needed) This one "pulses" it to the color you want (e.g. white) by putting a div background color behind it, and then fading the object out and in again. HTML object (e.g. button): <div style="background: #fff;"> <input type="submit" class="element" value="Whatever" /> </div> jQuery (vanilla, no other plugins): $('.element').fadeTo(100, 0.3, function() { $(this).fadeTo(500, 1.0); }); element - class name first number in fadeTo() - milliseconds for the transition second number in fadeTo() - opacity of the object after fade/unfade You may check this out in the lower right corner of this webpage: https://single.majlovesreg.one/v1/ Edit (willsteel) no duplicated selector by using $(this) and tweaked values to acutally perform a flash (as the OP requested).
You could use the highlight effect in jQuery UI to achieve the same, I guess.
If you're using jQueryUI, there is pulsate function in UI/Effects $("div").click(function () { $(this).effect("pulsate", { times:3 }, 2000); }); http://docs.jquery.com/UI/Effects/Pulsate
$('#district').css({opacity: 0}); $('#district').animate({opacity: 1}, 700 );
Pure jQuery solution. (no jquery-ui/animate/color needed.) If all you want is that yellow "flash" effect without loading jquery color: var flash = function(elements) { var opacity = 100; var color = "255, 255, 20" // has to be in this format since we use rgba var interval = setInterval(function() { opacity -= 3; if (opacity <= 0) clearInterval(interval); $(elements).css({background: "rgba("+color+", "+opacity/100+")"}); }, 30) }; Above script simply does 1s yellow fadeout, perfect for letting the user know the element was was updated or something similar. Usage: flash($('#your-element'))
You could use this plugin (put it in a js file and use it via script-tag) http://plugins.jquery.com/project/color And then use something like this: jQuery.fn.flash = function( color, duration ) { var current = this.css( 'color' ); this.animate( { color: 'rgb(' + color + ')' }, duration / 2 ); this.animate( { color: current }, duration / 2 ); } This adds a 'flash' method to all jQuery objects: $( '#importantElement' ).flash( '255,0,0', 1000 );
You can extend Desheng Li's method further by allowing an iterations count to do multiple flashes like so: // Extend jquery with flashing for elements $.fn.flash = function(duration, iterations) { duration = duration || 1000; // Default to 1 second iterations = iterations || 1; // Default to 1 iteration var iterationDuration = Math.floor(duration / iterations); for (var i = 0; i < iterations; i++) { this.fadeOut(iterationDuration).fadeIn(iterationDuration); } return this; } Then you can call the method with a time and number of flashes: $("#someElementId").flash(1000, 4); // Flash 4 times over a period of 1 second
How about a really simple answer? $('selector').fadeTo('fast',0).fadeTo('fast',1).fadeTo('fast',0).fadeTo('fast',1) Blinks twice...that's all folks!
I can't believe this isn't on this question yet. All you gotta do: ("#someElement").show('highlight',{color: '#C8FB5E'},'fast'); This does exactly what you want it to do, is super easy, works for both show() and hide() methods.
This may be a more up-to-date answer, and is shorter, as things have been consolidated somewhat since this post. Requires jquery-ui-effect-highlight. $("div").click(function () { $(this).effect("highlight", {}, 3000); }); http://docs.jquery.com/UI/Effects/Highlight
function pulse() { $('.blink').fadeIn(300).fadeOut(500); } setInterval(pulse, 1000);
I was looking for a solution to this problem but without relying on jQuery UI. This is what I came up with and it works for me (no plugins, just Javascript and jQuery); -- Heres the working fiddle -- http://jsfiddle.net/CriddleCraddle/yYcaY/2/ Set the current CSS parameter in your CSS file as normal css, and create a new class that just handles the parameter to change i.e. background-color, and set it to '!important' to override the default behavior. like this... .button_flash { background-color: #8DABFF !important; }//This is the color to change to. Then just use the function below and pass in the DOM element as a string, an integer for the number of times you would want the flash to occur, the class you want to change to, and an integer for delay. Note: If you pass in an even number for the 'times' variable, you will end up with the class you started with, and if you pass an odd number you will end up with the toggled class. Both are useful for different things. I use the 'i' to change the delay time, or they would all fire at the same time and the effect would be lost. function flashIt(element, times, klass, delay){ for (var i=0; i < times; i++){ setTimeout(function(){ $(element).toggleClass(klass); }, delay + (300 * i)); }; }; //Then run the following code with either another delay to delay the original start, or // without another delay. I have provided both options below. //without a start delay just call flashIt('.info_status button', 10, 'button_flash', 500) //with a start delay just call setTimeout(function(){ flashIt('.info_status button', 10, 'button_flash', 500) }, 4700); // Just change the 4700 above to your liking for the start delay. In this case, //I need about five seconds before the flash started.
Would a pulse effect(offline) JQuery plugin be appropriate for what you are looking for ? You can add a duration for limiting the pulse effect in time. As mentioned by J-P in the comments, there is now his updated pulse plugin. See his GitHub repo. And here is a demo.
Found this many moons later but if anyone cares, it seems like this is a nice way to get something to flash permanently: $( "#someDiv" ).hide(); setInterval(function(){ $( "#someDiv" ).fadeIn(1000).fadeOut(1000); },0)
The following codes work for me. Define two fade-in and fade-out functions and put them in each other's callback. var fIn = function() { $(this).fadeIn(300, fOut); }; var fOut = function() { $(this).fadeOut(300, fIn); }; $('#element').fadeOut(300, fIn); The following controls the times of flashes: var count = 3; var fIn = function() { $(this).fadeIn(300, fOut); }; var fOut = function() { if (--count > 0) $(this).fadeOut(300, fIn); }; $('#element').fadeOut(300, fIn);
If including a library is overkill here is a solution that is guaranteed to work. $('div').click(function() { $(this).css('background-color','#FFFFCC'); setTimeout(function() { $(this).fadeOut('slow').fadeIn('slow'); } , 1000); setTimeout(function() { $(this).css('background-color','#FFFFFF'); } , 1000); }); Setup event trigger Set the background color of block element Inside setTimeout use fadeOut and fadeIn to create a little animation effect. Inside second setTimeout reset default background color Tested in a few browsers and it works nicely.
Like fadein / fadeout you could use animate css / delay $(this).stop(true, true).animate({opacity: 0.1}, 100).delay(100).animate({opacity: 1}, 100).animate({opacity: 0.1}, 100).delay(100).animate({opacity: 1}, 100); Simple and flexible
$("#someElement").fadeTo(3000, 0.3 ).fadeTo(3000, 1).fadeTo(3000, 0.3 ).fadeTo(3000, 1); 3000 is 3 seconds From opacity 1 it is faded to 0.3, then to 1 and so on. You can stack more of these. Only jQuery is needed. :)
There is a workaround for the animate background bug. This gist includes an example of a simple highlight method and its use. /* BEGIN jquery color */ (function(jQuery){jQuery.each(['backgroundColor','borderBottomColor','borderLeftColor','borderRightColor','borderTopColor','color','outlineColor'],function(i,attr){jQuery.fx.step[attr]=function(fx){if(!fx.colorInit){fx.start=getColor(fx.elem,attr);fx.end=getRGB(fx.end);fx.colorInit=true;} fx.elem.style[attr]="rgb("+[Math.max(Math.min(parseInt((fx.pos*(fx.end[0]-fx.start[0]))+fx.start[0]),255),0),Math.max(Math.min(parseInt((fx.pos*(fx.end[1]-fx.start[1]))+fx.start[1]),255),0),Math.max(Math.min(parseInt((fx.pos*(fx.end[2]-fx.start[2]))+fx.start[2]),255),0)].join(",")+")";}});function getRGB(color){var result;if(color&&color.constructor==Array&&color.length==3) return color;if(result=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) return[parseInt(result[1]),parseInt(result[2]),parseInt(result[3])];if(result=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) return[parseFloat(result[1])*2.55,parseFloat(result[2])*2.55,parseFloat(result[3])*2.55];if(result=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) return[parseInt(result[1],16),parseInt(result[2],16),parseInt(result[3],16)];if(result=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) return[parseInt(result[1]+result[1],16),parseInt(result[2]+result[2],16),parseInt(result[3]+result[3],16)];if(result=/rgba\(0, 0, 0, 0\)/.exec(color)) return colors['transparent'];return colors[jQuery.trim(color).toLowerCase()];} function getColor(elem,attr){var color;do{color=jQuery.curCSS(elem,attr);if(color!=''&&color!='transparent'||jQuery.nodeName(elem,"body")) break;attr="backgroundColor";}while(elem=elem.parentNode);return getRGB(color);};var colors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};})(jQuery); /* END jquery color */ /* BEGIN highlight */ jQuery(function() { $.fn.highlight = function(options) { options = (options) ? options : {start_color:"#ff0",end_color:"#fff",delay:1500}; $(this).each(function() { $(this).stop().css({"background-color":options.start_color}).animate({"background-color":options.end_color},options.delay); }); } }); /* END highlight */ /* BEGIN highlight example */ $(".some-elements").highlight(); /* END highlight example */ https://gist.github.com/1068231
Unfortunately the top answer requires JQuery UI. http://api.jquery.com/animate/ Here is a vanilla JQuery solution http://jsfiddle.net/EfKBg/ JS var flash = "<div class='flash'></div>"; $(".hello").prepend(flash); $('.flash').show().fadeOut('slow'); CSS .flash { background-color: yellow; display: none; position: absolute; width: 100%; height: 100%; } HTML <div class="hello">Hello World!</div>
Here's a slightly improved version of colbeerhey's solution. I added a return statement so that, in true jQuery form, we chain events after calling the animation. I've also added the arguments to clear the queue and jump to the end of an animation. // Adds a highlight effect $.fn.animateHighlight = function(highlightColor, duration) { var highlightBg = highlightColor || "#FFFF9C"; var animateMs = duration || 1500; this.stop(true,true); var originalBg = this.css("backgroundColor"); return this.css("background-color", highlightBg).animate({backgroundColor: originalBg}, animateMs); };
This one will pulsate an element's background color until a mouseover event is triggered $.fn.pulseNotify = function(color, duration) { var This = $(this); console.log(This); var pulseColor = color || "#337"; var pulseTime = duration || 3000; var origBg = This.css("background-color"); var stop = false; This.bind('mouseover.flashPulse', function() { stop = true; This.stop(); This.unbind('mouseover.flashPulse'); This.css('background-color', origBg); }) function loop() { console.log(This); if( !stop ) { This.animate({backgroundColor: pulseColor}, pulseTime/3, function(){ This.animate({backgroundColor: origBg}, (pulseTime/3)*2, 'easeInCirc', loop); }); } } loop(); return This; }
Put this together from all of the above - an easy solution for flashing an element and return to the original bgcolour... $.fn.flash = function (highlightColor, duration, iterations) { var highlightBg = highlightColor || "#FFFF9C"; var animateMs = duration || 1500; var originalBg = this.css('backgroundColor'); var flashString = 'this'; for (var i = 0; i < iterations; i++) { flashString = flashString + '.animate({ backgroundColor: highlightBg }, animateMs).animate({ backgroundColor: originalBg }, animateMs)'; } eval(flashString); } Use like this: $('<some element>').flash('#ffffc0', 1000, 3); Hope this helps!
Here's a solution that uses a mix of jQuery and CSS3 animations. http://jsfiddle.net/padfv0u9/2/ Essentially you start by changing the color to your "flash" color, and then use a CSS3 animation to let the color fade out. You need to change the transition duration in order for the initial "flash" to be faster than the fade. $(element).removeClass("transition-duration-medium"); $(element).addClass("transition-duration-instant"); $(element).addClass("ko-flash"); setTimeout(function () { $(element).removeClass("transition-duration-instant"); $(element).addClass("transition-duration-medium"); $(element).removeClass("ko-flash"); }, 500); Where the CSS classes are as follows. .ko-flash { background-color: yellow; } .transition-duration-instant { -webkit-transition-duration: 0s; -moz-transition-duration: 0s; -o-transition-duration: 0s; transition-duration: 0s; } .transition-duration-medium { -webkit-transition-duration: 1s; -moz-transition-duration: 1s; -o-transition-duration: 1s; transition-duration: 1s; }
just give elem.fadeOut(10).fadeIn(10);
This is generic enough that you can write whatever code you like to animate. You can even decrease the delay from 300ms to 33ms and fade colors, etc. // Flash linked to hash. var hash = location.hash.substr(1); if (hash) { hash = $("#" + hash); var color = hash.css("color"), count = 1; function hashFade () { if (++count < 7) setTimeout(hashFade, 300); hash.css("color", count % 2 ? color : "red"); } hashFade(); }
you can use jquery Pulsate plugin to force to focus the attention on any html element with control over speed and repeatation and color. JQuery.pulsate() * with Demos sample initializer: $(".pulse4").pulsate({speed:2500}) $(".CommandBox button:visible").pulsate({ color: "#f00", speed: 200, reach: 85, repeat: 15 })
How to combine jQuery animate with css3 properties without using css transitions?
In this example; i am trying to create a jQuery animation with css3 rotate property. I can manage this animation with css3 transition and jQuery css() but i want to do this with jQuery animate() for rotating deg value according to my jQuery variatons. Is it possible use animate with css3 property value with jQuery 1.8.0? Here is jsFiddle to inspect. jQuery: var rotateVal = 90; //this method isn't working $('.red').animate({ 'transform':'rotate('+rotateVal+'deg)' },500); //this way works but i don't want to do this with transitions $('.black').css({ 'transform':'rotate('+rotateVal+'deg)', 'transition':'1s' }); html: <span class="black"></span> <span class="red"></span> Edit: Vendor prefixes removed, like -webkit-. Thanks to Kevin B.
It is possible, but it isn't easy. var red = $(".red"), rotateVal = 90; $("<div />").animate({ height: rotateVal },{ duration: 500, step: function(now){ red.css('transform','rotate('+now+'deg)'); } }); This basically creates a fake animation of a detached div, then on each step, updates the rotation of the target div. Edit: Oops! wrong argument order. Here's a demo. http://jsfiddle.net/qZRdZ/ note that in 1.8.0 i don't think you need to specify all the vendor prefixes. Using this method, you can animate almost anything as long as you keep in mind that things like += and -= won't work properly unless coded for. Update: Here's a combination of my solution and cuzzea's solution abstracted behind a function. http://jsfiddle.net/qZRdZ/206/ $.fn.rotate = function(start, end, duration) { console.log(this); var _this = this; var fakeDiv = $("<div />"); _this.promise().done(function(){ _this.animate({"a":end},{duration:duration}); fakeDiv.css("height", start).animate({ height: end }, { duration: duration, step: function(now) { _this.css("transform", "rotate(" + now + "deg)"); }, complete: function() { fakeDiv.remove(); } }); }); return _this; }; var red = $('.red'); red.click(function() { if ( !$(this).is(':animated') ) { red.rotate(45,135,500); setTimeout(function(){ red.rotate(135,190,500); },750); setTimeout(function(){ red.rotate(190,45,500); },1500); } }); });
Kevin is corect, almost. :) Here is working jsFiddle. You don't have to use another element and height, you can do something like: var red = $('.red'), max_rot = 45, start_from = 90; red.css({a:0}).animate( {'a':1}, { step: function(value,tweenEvent) { rotateVal = start_from + max_rot * value; red.css({ 'transform':'rotate('+rotateVal+'deg)', }); } }, 1000); The ideea is simple. First we create a bogus css property 'a' and set it to 0, and then we animate it to 1, so the step function will give you a value of 0 to 1 that you can use to set the custom transform.
An alternative method would be to use jQuery to change the dom to something that css would respond to. We can set our css to look like this: .object { -webkit-transition:all .4s; -moz-transform:all .4s; -o-transform:all .4s; -ms-transform:all .4s; transform:all .4s; } .object[data-rotate="false"] { -webkit-transform:rotate(0deg); -moz-transform:rotate(0deg); -o-transform:rotate(0deg); -ms-transform:rotate(0deg); transform:rotate(0deg); } .object[data-rotate="true"] { -webkit-transform:rotate(90deg); -moz-transform:rotate(90deg); -o-transform:rotate(90deg); -ms-transform:rotate(90deg); transform:rotate(90deg); } Our jQuery would look like this: $('#trigger').live('click',function(){ if($('.object').attr('data-rotate') = true) { $('.object').attr('data-rotate',false); } else { $('.object').attr('data-rotate', true); } }); Obviously, the browser has to support the ability to transform whatever animation you want to run, so its its hit or miss depending on the type of animation, but its nicer to work with if you have a ton of stuff going on or you have some children you want to animate concurrently. Example fiddle: http://jsfiddle.net/ddhboy/9DHDy/1/
CSS3 Smooth transition when dynamically changing animations
I have two keyframe animations "Bounce-In" and "Bounce-Out" the Bounce-In animation takes 1.2 seconds to complete, but if a user triggers the Bounce-Out function before it's finished it will jump to 100% scale and doesn't gracefully scale out from it's current animation position. Is this possible with keyframe animations? I've seen it done with transition property but not using scale(). #-webkit-keyframes Bounce-In { 0% { -webkit-transform: scale(0) } 40% { -webkit-transform: scale(1.0) } 60% { -webkit-transform: scale(0.7) } 80% { -webkit-transform: scale(1.0) } 90% { -webkit-transform: scale(0.9) } 100% { -webkit-transform: scale(1.0) } } #-webkit-keyframes Bounce-Out { 0% { -webkit-transform: scale(1.0) } 40% { -webkit-transform: scale(0.1) } 60% { -webkit-transform: scale(0.4) } 80% { -webkit-transform: scale(0.1) } 90% { -webkit-transform: scale(0.2) } 100% { -webkit-transform: scale(0) } } I have a demo on JSFiddle: http://jsfiddle.net/Vn3bM/98/ *if you click the "Games" circle before the animation is finished you will notice the other two jump to 100% and then animate out (that's what I'm trying to make smooth). I even tried removing the 0% keyframe from Bounce-Out and that didn't help...
In your case, the "jump" you notice in your animation comes from the change of animations you have installed on onmouseup. The "Bounce-Out" Animation has an initial scale of 1 (first Keyframe), and this is what the two circles immediately get set to when the animation is installed. There are two solutions to this, which I can explain in some detail: The Easy Way You could just wait for the initial animation to end via the 'webkitAnimationEnd' Event and install the onmouseup event with a recursive function waiting for the animation to finish: var initAnimationEnded = false; document.getElementById('sports').addEventListener('webkitAnimationEnd', function() { initAnimationEnded = true; }, false); And here's the onmouseup handler: document.getElementById('games').onmouseup = function() { function bounceOut() { if (initAnimationEnded) { events.style.webkitAnimationName = "Bounce-Out"; sports.style.webkitAnimationDelay = "0.2s"; sports.style.webkitAnimationName = "Bounce-Out"; } else { setTimeout(bounceOut, 20); } } bounceOut(); } I installed a jsfiddle here so you can see it working. The Bounce Out animation is only triggered after the animation finished, nothing unusual about that. The Hard Way You can pause the animation and parse the current values of the transformation, then install a temporary keyframe animation to bounce out. This gets much more verbose though: First, you have to stop the animations: events.style.webkitAnimationPlayState = "paused"; sports.style.webkitAnimationPlayState = "paused"; Then, you set up a helper to insert new css rules: var addCssRule = function(rule) { var style = document.createElement('style'); style.innerHTML = rule; document.head.appendChild(style); } Then create the css keyframe rules on the fly and insert them: // get the current transform scale of sports and events function getCurrentScaleValue(elem) { return document.defaultView. getComputedStyle(elem, null). getPropertyValue('-webkit-transform'). match(/matrix\(([\d.]+)/)[1]; } var currentSportsScale = getCurrentScaleValue(sports); var currentEventsScale = getCurrentScaleValue(events); // set up the first string for the keyframes rule var sportsTempAnimation = ['#-webkit-keyframes Sports-Temp-Bounce-Out {']; var eventsTempAnimation = ['#-webkit-keyframes Events-Temp-Bounce-Out {']; // basic bounce out animation var bounceOutAnimationBase = { '0%': 1, '40%': 0.1, '60%': 0.4, '80%': 0.1, '90%': 0.2, '100%': 0 }; // scale the animation to the current values for (prop in bounceOutAnimationBase) { sportsTempAnimation.push([ prop, ' { -webkit-transform: scale(', currentSportsScale * bounceOutAnimationBase[prop], ') } '].join('')); eventsTempAnimation.push([ prop, ' { -webkit-transform: scale(', currentEventsScale * bounceOutAnimationBase[prop], ') } ' ].join('')); } // add closing brackets sportsTempAnimation.push('}'); eventsTempAnimation.push('}'); // add the animations to the rules addCssRule([sportsTempAnimation.join(''), eventsTempAnimation.join('')].join(' ')); Then, you restart the animations with these rules: events.style.webkitAnimationName = "Events-Temp-Bounce-Out"; events.style.webkitAnimationDelay = "0s"; sports.style.webkitAnimationDelay = "0s"; sports.style.webkitAnimationName = "Sports-Temp-Bounce-Out"; events.style.webkitAnimationPlayState = "running"; sports.style.webkitAnimationPlayState = "running"; Et voilà. I made a jsfiddle here so you can play around with it. More Sugar In your example, the circles bounce out alternating in bounce. You can easily get this back to work with the second solution by using setTimeout for all sports circle animations. I did not want to include it here because it would unnecessarily complicate the example code. I know the provided examples are not really DRY, you could for example make all the stuff for events and sports work with half the lines of code (with meta properties), but in terms of readability, I think this example serves well. To have this example working in all browsers with support for css3 animations, you need to normalize the transition properties. To do this in javascript, have a look here The Example works for animations and other properties as well, just replace 'transition' with the property you want For a further read on modifying css3 animations on the fly, I found this post very useful, have a look at it as well.
Using CSS3 to make a smooth slow scroll
Basically I have a banner of images which are to scroll from left to right. I have it working fine with jQuery (code pasted below) however it can be very jittery and the client wants it smoother. So after some research the best way is to use CSS3 (probably should have started here). I haven't used much CSS3 other than the basics like border-radius so had to read up. After seeing some examples I was able to try out making the scroll however I couldn't get it to work with jQuery as well. The intended effect: scroll slowly from right to left 'forever' when mouse is over it, it stops scrolling I do this with the following jQuery: $(document).ready(function() { var $scrollMe = $('.ScrollMe'); $scrollMe.hover(stopBannerAnimation) $scrollMe.mouseout(startBannerAnimation) function stopBannerAnimation() { $(this).stop(); } function startBannerAnimation() { /*if (Modernizr.csstransitions) { $scrollMe.css('left', '{xen:calc '{$scrollerWidth} * 100'}px'); } else*/ { $scrollMe.animate( {left: -{$scrollerWidth}}, {xen:calc '{$scrollerWidth} * 60'}, 'linear', function(){ if ($(this).css('left') == '{$scrollerWidth}px') { $(this).css('left', 0); startBannerAnimation(); } } ); } } startBannerAnimation(); $('.ScrollMe ol').clone().appendTo('.ScrollMe'); }); Can someone help me get this same functionality while using CSS3 to handle the actual scrolling so it is smoother (in theory)?
This is how I'd do it, using 5 seconds for the animation speed: Step 1: write your CSS3 transition class .ScrollMe{ -webkit-transition:left 5s ease; // here the animation is set on 5 seconds -moz-transition:left 5s ease; // adjust to whatever value you want -o-transition:left 5s ease; transition:left 5s ease;} } Step 2: set up the jquery to toggle the left position function DoAnimation () { var $scrollMe = $('.ScrollMe'); if ($scrollMe.offset().left === 0) { // I imagine you calculate $scrollerWidth elsewhere in your code?? $scrollMe.css('left', $scrollerWidth); } else { $scrollMe.css('left', 0); } setTimeout(function () { if (LaunchAnimation === true) { DoAnimation(); } }, 5000); // here also assuming 5 seconds; change as needed } Step 3: control animation start/stop var LaunchAnimation = true; $(document).ready(function() { $('.ScrollMe').mouseover(function () { //this stops the div from moving if (LaunchAnimation === true) { $(this).css('left', $(this).offset().left); LaunchAnimation = false; } }); $('.ScrollMe').mouseleave(function() { DoAnimation(); LaunchAnimation = true; }); } This way, you let the CSS rendering engine of the browser control the speed and movement of the div for smoothness and you use jquery only as the trigger mechanism. Hope this helps.