Parallax scroll with easing - javascript

I have an element that move relative to scroll. I use jQuery for this:
$('#object').css('transform','translateY('+($(window).scrollTop()*.4)+'px)');
CSS
#object {
width:200px;
top:100%;
left:50%;
position:absolute;
}
This works well, but moves my element directly without any easing (delay).
By setting a transition using css I get some of the effect that I'm looking for, but doesn't look good if I scroll at the same time:
transition: 400ms ease;
Is it possible to do this smooth, but in a more elegant way?

I figured it out by myself. The problem was the css "ease". Ease means that it will start slow and end slow, which will result in at the time scrolling is active it will always be on the slow start. However if you use css "ease-out" it will always start fast and slow down in the end. So use this:
transition: 400ms ease-out;
Or cubic-bezier if you want to customize the easing-curve yourself:
transition: 400ms cubic-bezier(0.235, 0.615, 0.185, 0.995);

When doing a parallax effect you will set a new translateY() on every scroll event that triggers. The event triggers really often and normally there should be no need for a transition. If you still experience bad rendering it is probably because the browser does not render on every event. You can force the browser to do so by using requestAnimationFrame.
var translate = function() {
$('#object').css('transform','translateY('+($(window).scrollTop()*.4)+'px)');
}
$(window).on('scroll', function() {
window.requestAnimationFrame(translate);
});

Related

How can I animate an element programmaticaly using JavaScript?

I am looking at this code http://codepen.io/optyler/pen/FgDyr and if you hover to the triangle element, you will see the animation. However instead of hovering it, I want to do it programmaticaly using JavaScript. This is what I have done so far:
document.querySelector('.triangle').classList.add('animateSpeak');
and added a new css class
.animateSpeak {
animation: vibrate .5s infinite ease-out;
}
The animation is working though as you can see here http://imgur.com/a/V9JyO the left part is only animating. Am I doing something wrong here?
Since you're using a CSS 3 animation, you would probably need some sort of active class.
Just change the :hover selectors (line 54) to, say, .active instead. i.e.:
.triangle.active,
.triangle.active:before,
.triangle.active:after {
animation: vibrate .5s infinite ease-out;
}
You can start the animation programmatically by adding the .active class or stop it be removing the class.
To answer your second question, it looks like the :before and :after elements need the animation too.
In your CSS add
.animateSpeak,
.animateSpeak:before,
.animateSpeak:after {
animation: vibrate .5s infinite ease-out;
}
Just a quick thought, you can avoid the intersection of the three becoming darker than their constituents by changing the color from rgba to rgb or a solid color,
$font_color: rgb(231,236,241);

What's the robust way to have JS callbacks wait on a CSS3 transition, iff the transition happens?

In the past with JS transitions, one could specify some behavior to happen after the transition, via a callback. E.g.
//jQuery
function hideTheContent() {
$('#content').fadeOut(1000,function() {
mandatoryLogicAfterHidingContent();
});
}
Now with CSS3 transitions, we can do something like this.
//CSS
#content {
opacity:1;
transition: opacity 1s;
}
.hidden {
opacity:0;
transition: opacity 1s;
}
//jQuery
function hideTheContent() {
$('#content').addClass('hidden');
// still need to run mandatoryLogicAfterHidingContent
}
I know of the new transitionend events, so hypothetically we could do something like this:
//jQuery
function hideTheContent() {
$('#content').on('transitionend', function(e) {
mandatoryLogicAfterHidingContent()
})
$('#content').addClass('hidden');
}
but since we're now separating out the JS from the UI, it's possible that someone else could come along with a new UI where content-hiding is instant, remove the CSS3 transition, and inadvertently break the JS call to mandatoryLogicAfterHidingContent().
Another scenario, say I have a box and there's a reset function that resizes said box to size 50x50 (with transition), then calls a mandatoryLogicAfterResize(). If I call the reset fn twice, I don't think the transition event is guaranteed to fire in this case - but I still need mandatoryLogicAfterResize to run both times.
In more complex codebases, I also worry about other transitions getting called before the specific transition I'm targeting. and prematurely triggering the mandatoryLogic(). I guess the core problem here is, with CSS3 transitions, how can I defensively tie the mandatoryLogicAfterHidingContent() event handler with my and only my invocation of addClass('hidden'), like I could with the jQuery callback?

Rewinding CSS animation

Let say I have a div
<div id='animate'></div>
and has an animation of:
#keyframes move{
from{transform:translateX(500px);}
to{transform:translateX(0px);}
}
And i have a button that when clicked will programatically set the animationDirection to reverse. But what happen is that it restart the animation and execute the animation in reverse. What I really want is reverse the animation from its current state(before the animation ends) without restarting.
Is that possible?
http://jsfiddle.net/fdZKw/
keyframe animations require a from (0%) and a to (100%) parameters, so unless you set these parameters on the fly via javascript, I don't think you can make it happen. Although, the transition property does what you want - https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions
I have applied it to your fiddle: http://jsfiddle.net/fdZKw/1/
#animate{
width:100px;
height:100px;
background:#0099CC;
transition:transform 5s;
-webkit-transition:-webkit-transform 5s;
}
#animate.go {
transform:translateX(500px);
-webkit-transform:translateX(500px);
}

Order CSS Styles with Transitions and JavaScript

if i apply a style to an element and immdiatily afterwards add css transition styles, the transition is applied to the style preceeding. this might not always be the intention.
i found a solution by using settimeout (0), is there any cleaner/more correct approach known ?
http://jsfiddle.net/nicib83/XP9E7/
$("div").css("opacity", 1);
$("div").css("-webkit-transition", "all 0.35s");
/* Works
window.setTimeout(function () {
$("div").css("-webkit-transition", "all 0.35s");
}, 0);
*/
best regards
Edit:
i didn't mean how best to set css styling but how to sequentially set styles when the first style should be applied without the second being active at that time but only afterwards, i wan to add transition afterwards. settimeout fixes it, best solution ?
It's much better to pre-define a class that contains both of the properties you want to apply, and add that class programmatically to the element. Both of the properties will be applied together.
.myClass {
opacity: 1;
-webkit-transition: all 0.35s;
}
$("div").addClass("myClass");
You could take a page from the book of Twitter Bootstrap:
fade {
opacity: 0;
-webkit-transition: opacity 0.15s linear;
-moz-transition:opacity 0.15s linear;
-o-transition:opacity 0.15s linear;
transition:opacity 0.15s linear;
}
.fade.in{
opacity:1;
}
then programatically add the .in class when you want it to fade in:
$("div").addClass("in");
with your original div looking something like:
<div class="fade">Box</div>
I've been running up against this myself and also found the setTimeout solution. After some research the issue is how the browser handles scheduling. The JavaScript runs in its own thread separate from the threads dealing with the UI and the DOM (which is why issues like UI blocking happen).
In cases like this both JavaScript statements run before the document registers the first change and it ends up applying both classes at the same time. setTimeout(fn,0) effectively makes the function asynchronous and shunts the functions to run at the next available opportunity. This allows the UI thread to catch up before the next class is added.

How to optimize the jquery animate code

Hi I am doing a zoom in & out using jquery animate. The problem is it is too slow and takes too much of time. The animate function is going to zoom approximately 100's of divs. Can some one please tell me what should be done to make it optimized. Here is the code below
//Zoom In by clicking the plus button
$("div#explanation .plus").click(function(){
jsPlumb.repaintEverything();
/* var strongFont = parseFloat($("div.window strong").css('font-size'));
var newStrongFont = strongFont + 2;
//alert("the new font is"+strongFont);
*/
$("div#demo1").animate({'height':'+=20', 'width':'+=20'});
$("div.window ").animate({
'height':'+=20px', 'width':'+=20px'
},0,function(){
jsPlumb.repaintEverything();
});
/* $("div.window strong").animate({
fontSize:newStrongFont
},0,function(){
jsPlumb.repaintEverything();
});
*/
});
I am having similar to zoom out. Please guide me. Thanks!
First off, you have to realize that you're almost certainly not going to get good performance aniating hundreds of elements. It's just too much for the browser to handle. I would try to animate a single container element to achieve whatever effect you're going after.
That said, you might want to take a look at the animate-enhanced plugin. In browsers that support CSS animation, the plugin automatically translates .animate(...) calls into CSS animations, which are usually hardware-accelerated. This gives much better performance than animate's usual method of changing an element's properties on a set interval.
You might also try using CSS animation directly if the plugin doesn't help. I'm not sure whether you're really trying to animate the size of the box or if you're trying to animate an actual zoom (where the box and all of its contents get bigger), but here's an example that animates the latter:
div {
width:200px;
height:200px;
background:red;
color:white;
margin:20px 50px;
padding:5px;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
}
div:hover {
-webkit-transform: scale(1.4);
-moz-transform: scale(1.4);
-webkit-animation-name: popin;
-moz-animation-name: popin;
-webkit-animation-duration: 350ms;
-moz-animation-duration: 350ms;
}
#-webkit-keyframes popin {
from {
-webkit-transform: scale(1);
}
to {
-webkit-transform: scale(1.4);
}
}
#-moz-keyframes popin {
from {
-moz-transform: scale(1);
}
to {
-moz-transform: scale(1.4);
}
}
The time for the animation to complete is something you can specify as the second argument to .animate(). You have not specified it so the default is 400ms. You can set it to whatever you want. The animation will always complete in approx the time that you set, but if there is too much work for the computer to do in that time to show you a smooth animation, you will get a jumpy one.
The only way to make an animation less jumpy is to optimize what you are animating or how you are animating it. Animating 100s of divs at the same time is probably more than anything but a very, very fast computer can do smoothly.
You will probably want to rethink what you are animating. One possible work-around in cases like this to animate an outline rather than the entire contents when the contents are really complex to animate with good performance.
If you want further help, you will have to show us more of the problem. We need to see the HTML you have so we can see what you're really trying to animate and we probably need to see the repaintEverything() function to see what it's doing.
If you're not too concerned about older browsers, you might be able to use css transform properties for this. They usually work quite quickly, allowing you to efficiently zoom in on a complicated section of the document. Here's a contrived example, which uses jQuery to zoom in on something whenever it's clicked. Animating would get more complicated: I don't believe jQuery's animate works with transform, but in theory you could repeatedly adjust the scale on a small level using timeouts.

Categories

Resources