Why are style assignments performed immediately after creation not animated? - javascript

Opening this fiddle on Webkit will show what I'm talking about.
How can I specify an element's style when it is first specified, and then its final state?
It should be possible to specify a single step animation fully this way (without having to start using #keyframes) but it seems like there is a lot of implementation specific strangeness I must deal with at this point. Note how in Firefox no animation is performed...

Seems to be the same issue as described here: CSS3 transitions to dynamically created elements
so
$("#one").on('click',function(){
var word = $("<div style='opacity: 0; height:0'>word</div>");
$('body').prepend(word);
window.getComputedStyle(word[0]).getPropertyValue("top");
word.css({height: 100, opacity: 1});
});
also works in this case: http://jsfiddle.net/wWnnH/3/

Alternatively, you can use jQuery.animate()
word.animate({height: 100, opacity: 1}, 5000);
Will work without the CSS, and on both webkit and mozilla. Although this defeats the purpose of trying to use CSS3 I guess.

Related

What is the cleanest way to animate without .animate() jQuery?

I had a nice idea, namely to use the 'stroke-dasharray' CSS-attribute that can be used on SVG objects, to stroke the paths on the page, giving it a nice artistic way for shapes to appear.
It works perfectly and is supported by most modern browsers as well as phones.
A nice jsfiddle of what I've made can be found here: http://jsfiddle.net/G6ECE/
The code that makes the whole thing tick right now:
num=0;
setInterval(function(){
updateStroke(num);
num+= 0.2;
}, 1);
function updateStroke(num){
// stroke-dasharray is a list of two or more numbers. In this example, percentage values are used to make all paths fully stroked at the end of the animation, irregardless of path length.
$('svg path').css({stroke:'#00FF00','stroke-dasharray':num+'% '+(100-num)+'%'});
}
Obviously this is a very basic, ugly way to animate something.
I want to customize the animation a little: I want to be able to add a custom animation length and also use different easings. Unfortunately, the jQuery $().animate() function that I'd normally use to animate CSS attributes, does not support non-numeric values.
As stroke-dasharray uses two or more numeric(pixel or percentage) values to work, I need an alternative for .animate()
What would be the cleanest way to do this? (with using as much existing jQuery functionality as possible, and as little as possible re-inventing an animation framework)
What about CSS transitions? They also have a better performance than jQuery animations.
http://www.w3schools.com/css/css3_transitions.asp
But be sure not to use both for the same property as jQuery animations interfere with CSS transitions.
Recently, I have been working with a nice robust cross-browser javascript animation object. Once you understand the way it is used, it becomes quite seamless for all or your SVG animations. It can be attached to any svg element and control associated values.
There are some examples that show the various choices of animation performance(linear, quadratic, ease,etc) at:
http://www.svgDiscovery.com/
Below is the object:
var AnimateJS=function(options){
this.options=options
var start = new Date
var iT = setInterval(
function(){
var timePassed = new Date - start
var progress = timePassed / options.duration
if (progress > 1) progress = 1
this.progress=progress
var delta = options.delta(progress)
options.output(delta)
if (progress == 1)clearInterval(iT);
},options.delay)
}

css animation fast forward and rewind

I was wondering if it was possible, using some javascript or jquery, to skip to the next, or go to the last part of a css animation. Lets say we have the following:
#keyframe effect{
0%{opacity:1;}
45%{opacity:1;}
50%{opacity:0;}
95%{opacity:0;}
100%{opacity:1;}
}
that will fade something out and then back in
so lets say I made some buttons. How would I do the following:
$('#next').click(function(){
//skip to the next animation part
});
$('#previous').click(function(){
//skip to the previous animation part
});
It's not really possible unless you break the CSS into different parts based on classes and then add/remove classes.
However, there is an absolutely fantastic javascript library called Greensock, that allows timeline-based animation - and in many cases is faster than CSS animations. It also has the benefit of being cross-browser compatible.
If you were, for example to create something similar using Greensock, it would look something like this:
var effect = new TimelineMax({paused:true});
effect.addLabel('start');
effect.to(
'#myItem',
1,
{css:{opacity:1}}
);
effect.addLabel('step1');
effect.to(
'#myItem',
1,
{css:{opacity:0}}
);
effect.addLabel('end');
effect.play();
$('#gotoEnd').on('click', function(e){
e.preventDefault();
effect.seek('end');
});
With the use of the animation-play-state Property, you can pause an animation and update the transform, then restart it.
element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";
However you can't pause the animation, transform it, resume it, and expect it to run fluidly from the new transformed state.
At this time, there is no way to get the exact current "percentage completed" of a CSS keyframe animation. The best method to approximate it is using a setInterval or requestAnimationFrame.
This CSS tricks article explains this further, and gives an example of using setInterval. Another option is to use request animation frame
As mentioned GreenSock or Velocity are animation libraries which allow for extremely fast and smooth animations

This seamless marquee style kind of jitters each scroll

I am using this code to create a scroll-up marquee text but after 7000 miliseconds it jitters and thus doesn't offer a good look for the text inside.
Have you any idea where I can fix it ?
<script language="javascript">
jQuery(function() {
var marquee = jQuery("#marquee");
marquee.css({"overflow": "hidden", "height": "100%"});
marquee.wrapInner("<span>");
marquee.find("span").css({ "height": "50%", "display": "inline-block", "text-align":"left" });
marquee.append(marquee.find("span").clone());
marquee.wrapInner("<div>");
marquee.find("div").css("height", "200%");
var reset = function() {
jQuery(this).css("margin-top", "0%");
jQuery(this).animate({ "margin-top": "-100%" }, 7000, 'linear', reset);
};
reset.call(marquee.find("div"));
});
BTW, you can it like this
<div id="marquee">text</div>
[UPDATE]Sorry Kamal for having to edit this post to add the jsfiddle to reproduce the problem [I always know I can do this :-D]
http://jsfiddle.net/xRcwH/
why not use the <marquee> tags?
<marquee behavior="scroll" direction="up">Your upward scrolling text goes here</marquee>
I've already answered the same question at <marquee> html tag usage/replacment.
There is CSS3 WebKit specific -webkit-marquee-, that you can read about at http://davidwalsh.name/webkit-marquee-css. However, for whatever reason, even the native CSS marquee implementation is glitchy.
The same applies to the <marquee> element. It is well supported by the browsers, though, apart from being deprecated, it is glitchy.
I've been looking for the most efficient and cross-browser supported marquee implementation. None of the above fit the bill. The common approach is to use timer (or jQuery animate implementation) to adjust the CSS margin property of the element. This is what your script does. Unfortunately, this operation is very resource intensive. It requires applying new CSS every few milliseconds resulting in recalculation of the whole layout.
I came up with implementation that utilises CSS3 transitions for browsers that support it and otherwise animate the scrollLeft property of the containing element. It is an experimental implementation, though it works well with IE7+. The code is available at https://github.com/gajus/marquee (demo https://dev.anuary.com/60244f3a-b8b2-5678-bce5-f7e8742f0c69/).

Order of properties matter with jQuery animate?

After just now spending too much time debugging why my jQuery animate() calls stopped working correctly, I realized my problem was the properties in the animate() call have to be in a specific order. So the following will not work properly:
$('div.example').animate({left: 50, top: 100, opacity: 1});
What will happen is the div.example will fade in (if it wasn't already) and will just appear at position left:50, top:100, it will not animate. To get this to work as expected, you have to reorder:
$('div.example').animate({opacity: 1, left: 50, top: 100});
I tested this in FF4 and Chrome. This surprised me as I wasn't even aware that Javascript guaranteed order of properties in objects and jQuery makes no mention of this requirement in their docs. So my question is basically, am I doing something wrong? Is this expected? Is there documentation on what the proper order is? Will this work properly in all browsers?
I'm using jQuery UI as well. I know that enhances the standard animate method to allow for animating colors and such. Is that potentially the issue?
This a jQuery bug: cannot animate position and opacity at same time but is fixed in 1.6.1
In the meantime, you can fix it by adding "px" on the end:
$('div.example').animate({top: '100px', left: '50px', opacity: 1});
Does your properties left and top are declared earlier in css? Some browsers (webkit if I remember correctly) have problems animating properties that weren't declared. Try setting left and top to 0 or some other values and see if it works.

jQuery example (in jsfiddle) working in firefox but not in IE8, 7

Why this example not working in IE http://jsfiddle.net/8RZVt/
I'm getting this error in IE8.
Message: Invalid argument.
Line: 156
Char: 295
Code: 0
URI: http://code.jquery.com/jquery-1.4.4.min.js
According to jQuery, this is because, as stated on the animate documentation page:
All animated properties should be a
single numeric value (except as noted
below); properties that are
non-numeric cannot be animated using
basic jQuery functionality....
So, in fact, in Firefox you are using undefined behavior. The correct thing to do would be to animate on backgroundPositionX, however Firefox does not support this.
There is, however, a jQuery plugin that does what you want:
http://plugins.jquery.com/project/backgroundPosition-Effect
Update
On closer inspection, the plugin does not support += or -= formats.
I hacked it into this example:
http://jsfiddle.net/CxqSs/ (See new example at bottom.)
Could definitely use some cleanup, and should probably be added to that plug-in, but it works in both browsers and doesn't rely on undefined behavior.
BTW, I don't know if it's worth noting, but if you leave this animation running a long time, it will eventually overflow the value and break. This could be overcome by animating the full length of the background image and then resetting the offset to 0px in the callback before the next animate. This would also avoid needing the += format.
Also,
It should be noted that speed: 1, step: 1 and speed: 50, step: 50 are equivalent.
The reason they look different speeds is because
There is more overhead in a speed of 1 (which is really a millisecond duration) because animate gets called more often.
The default easing is "swing", meaning that the animation speeds up and slows down slightly throughout it's course, meaning that the overall speed is affected a bit. You should change the easing to "linear" for your scrolling case:
var animate = function() {
element.animate({
...
}, speed, "linear", animate);
};
This means that you could use the backgroundPosition-Effect plugin, without the '+=', by setting your step to 2247 (the width of the image), like I stated above.
And that finally brings us to... wait for it...
http://jsfiddle.net/zyQj3/20/
Cross-platform, non-kludgy, non-overflowing, correctly easing, extra parameter-lacking, solution.
The script fails at this point because you are passing an invalid CSS value:
element.animate({
backgroundPosition: animStep + " 0px" /* evaluates to "+=50px 0px" */
}, speed, animate);
OK here we go again :D
http://jsfiddle.net/c7rKV/1/
Again identical to original however again just animating backgroundPositionX when in IE.
Apologies on not actually looking at FF/Chrome last time.
Additionally: this of course is not very graceful and Adam Prax is absolutely correct on what the problem is. I just wanted to post a solution to it.
If you check the source code of jQuery, you will see it uses this regexp to parse the parameter (which in your case is +=50px 0px). So it will see it as += (increase) 50 (to fifty) px 0px (unit, append after the number). When trying to read the current value, jQuery uses parseFloat, which just grabs the number at the start of the string. So it works perfectly, even if a multi-dimensional property is probably not what the jQuery programmers had in mind.
Except that IE8 does not support getting the current value of background-position. There is background-position-x and background-position-y but no background-position. Duh. So your best bet is checking the browser type, and animating either background-position or background-position-x depending on that: http://jsfiddle.net/22UWW/
(There is actually a jQuery bug report about this, with a more elegant solution.)

Categories

Resources