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.
Related
So after a lot of searching about an issue that I am having, I figured out that the issue that I am having is, because when I apply css to the element, the info is not immediatelly available, here is what I mean:
I have an element that I am hiding and showing with display: block; and display: none;, the issue is that right after I show the element, I need to obtain its height:
$element.css({ display: "block"});
console.log($element.outerHeight()); // <- this returns 0
So I started experimenting with timeouts at some point, and even with a 1ms timeout, it still works and returns the correct height:
setTimeout(() => {
console.log($element.outerHeight()); // with 1ms timeout, it works and gives real height
}, 1)
After figuring that out, with 1 ms delay it could not be some inherited transition or anything, so that got me thinking that maybe, between the jump from display: block; to .outerHeight() something is not yet updated, after some digging I found this:
Quote: "You'll see different behaviors in different browsers since jQuery is updating the markup with inline styles and the browser decides when to repaint."
Does jQuery's css method block until the change is fully applied?
And this seems to be my actual problem, so the question now is, how do I figure out when that repainting has happened, I have tried with onload, load events but none of them get triggered.
I have also tried the suggested code in that post with animation:
$element.animate({
display: 'block'
}, {
duration: 0,
done: function(animation, jumpedToEnd) {
console.log($element.outerHeight());
}
})
But that did not work either.
The issue you are having is that you do not really have control on how the browser is displaying changes. The information is not immediately available, as you have pointed out and even though doing timeouts is technically a solution, it lacks elegance and endangers your UI of getting into callback hell.
What you will need to test in order to see whether more elegant solutions work is
1. Whether it works with 0 milliseconds
If it works with 0 milliseconds, then basically the UI is refreshed just after the function is successfully executed and before the next function from the event loop is running.
2. Whether doing it without jQuery behaves differently
Compare the behavior of
$element.css({ display: "block"});
with
for (let index = 0; index < $element.length; index++) {
$element[index].style.display = "block";
}
is equivalent. If so, then it's not a jQuery problem. If not, then it's a jQuery problem.
Conclusion
As a general guidance, you will probably need a callback-like behavior and to achieve that you will probably want to use the promise architecture. If it works.
I seriously have a question about the scroll event. I tried to solve it all night but I couldnt.
I am trying stick a navigation on the top. The stick effect will process when $(window).scrollTop() pass the point right before the navigation.
The problem is, there will have a "blink" effect (its like delay process) on IE and Chrome but not on Firefox.
While on my research I knew that Firefox has "smooth scroll" by default.
However, please check this example on Chrome or IE
http://www.backslash.gr/demos/jquery-sticky-navigation/
It is so smooth like on Firefox, and the code is just that simple......
The point is, I am doing the exactly same thing like this example but why I have the 'blink' effect??
Is the trick on CSS ??
Is there any way that I can create a smooth scrool like what on firefox by js??
Thank you very much for your help.
$(window).on('scroll', Sticky);
function Sticky(){
$(this).scrollTop() > anchor.offset().top
? nav.css({ 'position': 'fixed',
'z-index': z_index,
top: y,
left: x, })
: nav.css({ 'position': 'static', });
};
I think you might be confusing two things here.
looking at the working code you have linked to. there is a blink in there if you scroll on chrome or IE or firefox using your mouse scroller.
The blink is because you are changing position suddenly. Try to change the js so it does animate the position rather than suddenly changing its value.
As others have said linking to a working code and expecting an answer by showing a trick might not help all of us. Try to add animate on position change line of js and see if that helps.
There is no trick here. Its all in code so read the source and enjoy.
Looking at the incomplete example code it's really hard to determine what's going on, so please either update your question with complete code, or better - upload a JSFiddle to serve us as an example and we can directly update it with necessary changes. So far (based on what I said before) it looks like you're getting a flickering effect due to typos in your example code:
? nav.css({ 'position': 'fixed',
'z-index': z_index,
top: y,
left: x, })
: nav.css({ 'position': 'static', });
where you're not terminating the array of CSS properties and values that needs to be applied (you're ending it with a comma ,), and you've not enclosed some CSS properties in a single quote '. Your code should be:
? nav.css({ 'position': 'fixed',
'z-index': z_index,
'top': y,
'left': x })
: nav.css({ 'position': 'static' });
That's of course provided you've already set variables z_index, y and x beforehand.
EDIT & DISCLAIMER: I've created a new JSFiddle with the original demo code. The demo you referred to is copyrighted, so please attribute your gratitude to the original author and not me, if that helps you out. The code I've posted JSFiddle with is available as a free download, though. So I guess it's OK to reuse it for demo purposes as well. Change that code to comply with your requirements and update it to new version each step you update it. It will help you track where you're doing something wrong (if at all). ;)
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.
Here's the breakdown...
wrapper (position:relative; overflow:hidden; )
section-container (position:absolute)
multiple child sections
I attach a mousewheel event listener and animate (with easing) the 'top' position of 'section-container'. As this position changes, the 'background-position' of each section moves vertically based on the position of 'section-container's 'top' property (continually updated through a setTimeout()).
All of that works as it should, except as the 'background-position' changes, the image has a bit of a jitter. This doesn't happen if the 'background-attachment' is set to 'fixed'... but I don't want that.
Can anyone explain this, with a possible fix? I continually refer to the https://victoriabeckham.landrover.com/ site and can't figure out what they're doing differently to get theirs operating so efficiently.
You can check this out, i believe its where they do most of the animating:
https://victoriabeckham.landrover.com/js/ScrollAnimator.js?v=471
I would have to say they have some kind of framework that they are using to accomplish this.
EDIT: Sorry didn't see the new answer above mine, seems like a good starting point.
-Ken
If you inspect this website carefully, you will able to use it like landrover site.
You need to use: scrollTo plugin and parallax plugin
And document jQuery should be like this:
$(document).ready(function(){
$('#nav').localScroll(800);
//.parallax(xPosition, speedFactor, outerHeight) options:
//xPosition - Horizontal position of the element
//inertia - speed to move relative to vertical scroll. Example: 0.1 is one tenth the speed of scrolling, 2 is twice the speed of scrolling
//outerHeight (true/false) - Whether or not jQuery should use it's outerHeight option to determine when a section is in the viewport
$('#intro').parallax("50%", 0.1);
$('#second').parallax("50%", 0.1);
$('.bg').parallax("50%", 0.4);
$('#third').parallax("50%", 0.3);
});
Ok. So I figured out my issue was when trying to animate() the 'section-container' on the 'top' property. I was using a "+=" to allow it to increment from its current position. Not a good idea when using 'mousewheel' events. I changed it to a hard-set variable that is continually incremented/decremented.
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.)