I have the following script to create a parallax effect on the page using request animation frame, it runs well on Chrome, but on Safari is lagging, I think because I run too many calculations on each rAF.
$('.parallax').each(function () {
var section = $(this),
elements = section.find('[data-parallax-ratio]');
elements.data('parallax-current', 0);
function animation() {
var scrollPos = $(window).scrollTop(),
offsetY = section.offset().top - 60;
for (var i = 0; i < elements.length; i++) {
var el = $(elements[i]),
ratio = el.data('parallax-ratio'),
current = el.data('parallax-current');
var newPos = (offsetY - scrollPos) * ratio;
var pos = current - ((current - newPos) * 0.08);
el.css('transform', 'translateY(' + pos + 'px)');
el.data('parallax-current', pos);
}
window.requestAnimationFrame(animation);
}
animation();
});
-
\$\begingroup\$ Follow-up question \$\endgroup\$200_success– 200_success2016年05月26日 14:06:28 +00:00Commented May 26, 2016 at 14:06
1 Answer 1
The major issue that I see in your code is that you keep requestAnimationFrame
no matter what. This obviously causes the browser to update the css of the element at any time.
(削除) Since your animation is based on scroll I would suggest to define an handler to window.onscroll
. (削除ここまで)
While doing this you perhaps may wish to transform your animation
method to be a plugin method that you would call for every parallax
element.
Resulting code becomes something like this:
$.fn.parallaxAnimate = function() {
var elements = this.find('[data-parallax-ratio]');
var scrollPos = $(window).scrollTop(),
offsetY = this.offset().top - 60;
for (var i = 0; i < elements.length; i++) {
var el = $(elements[i]),
ratio = el.data('parallax-ratio'),
current = el.data('parallax-current') || 0;
var newPos = (offsetY - scrollPos) * ratio;
var pos = current - ((current - newPos) * 0.08);
el.css('transform', 'translateY(' + pos + 'px)');
el.data('parallax-current', pos);
}
}
(削除)
window.onscroll = function(){
$('.parallax').parallaxAnimate();
};
(削除ここまで)
Edit: I was wrong on my previous attempt to solve smoothness and I was also wrong about subscribing onscroll
I tried to solve the problem that the OP is having as the animation is not smooth. On my previous attempt I tried to implement a scroll animation on a scroll event, and I got a warning on firefox (this is a free translation since I got my browser on portuguese unfortunately):
This site appears to use a scroll-linked position effect. This may not work properly with asynchronous panning. See https://developers.mozilla.org/docs/Mozilla/Performance/ScrollLinkedEffects for more details...
And there you can read an explanation of what are the causes of this warning.
Meanwhile, on this same documentation page on Other effects
, you can have a link to a useful site that implements many scroll effects, one of those being the parallax. All of this only with css...
I will post here one smaller example based on the implementation of the site, give props to that man please, not to me ;).
<style>
/* Parallax base styles
--------------------------------------------- */
.parallax {
height: 500px; /* fallback for older browsers */
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
-webkit-perspective: 300px;
perspective: 300px;
}
.parallax__group {
position: relative;
height: 500px; /* fallback for older browsers */
height: 100vh;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.parallax__layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.parallax__layer--fore {
-webkit-transform: translateZ(90px) scale(.7);
transform: translateZ(90px) scale(.7);
z-index: 1;
}
.parallax__layer--base {
-webkit-transform: translateZ(0);
transform: translateZ(0);
z-index: 4;
}
.parallax__layer--back {
-webkit-transform: translateZ(-300px) scale(2);
transform: translateZ(-300px) scale(2);
z-index: 3;
}
.parallax__layer--deep {
-webkit-transform: translateZ(-600px) scale(3);
transform: translateZ(-600px) scale(3);
z-index: 2;
}
.parallax {
font-size: 200%;
}
/* centre the content in the parallax layers */
.title {
text-align: center;
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
#group1 {
z-index: 5; /* slide over group 2 */
}
#group1 .parallax__layer--base {
background: rgb(102,204,102);
}
#group2 {
z-index: 3; /* slide under groups 1 and 3 */
}
#group2 .parallax__layer--back {
background: rgb(123,210,102);
}
</style>
<div class="parallax">
<div id="group1" class="parallax__group">
<div class="parallax__layer parallax__layer--base">
<div class="title">Base Layer</div>
</div>
</div>
<div id="group2" class="parallax__group">
<div class="parallax__layer parallax__layer--base">
<div class="title">Base Layer</div>
</div>
<div class="parallax__layer parallax__layer--back">
<div class="title">Background Layer</div>
</div>
</div>
</div>
-
\$\begingroup\$ Obrigado Bruno! I'm gonna try to implement your version tonight and see how it runs. Also the reason I use requestAnimationFrame is because I wanted it to run on every frame to make the animation a little smoother. I'm afraid that with your code it might be a little "jumpy", I will test and let you know. Cheers \$\endgroup\$Valeriu Timbuc– Valeriu Timbuc2016年05月24日 17:01:01 +00:00Commented May 24, 2016 at 17:01
-
\$\begingroup\$ Hey man, I implemented your version, but it's not running as well, here's why. With requestAnimationFrame the function was running every frame and it created a smooth effect while scrolling, with your code it only runs on scroll, so if the user scrolls with the mouse wheel, the animation is jumpy and you cant notice that the boxes are moving. I have tried to run rAF on scroll start and keep it running for 1 sec after scroll end, but cancelAnimationFrame doesn't work, I think it's because Im not doing it properly and rAF runs again after cAF. \$\endgroup\$Valeriu Timbuc– Valeriu Timbuc2016年05月25日 09:17:55 +00:00Commented May 25, 2016 at 9:17
-
\$\begingroup\$ @ValeriuTimbuc Does something like this work? Unfortantly I think the algorithm I provided is a bit off I will try to fiddle with it a bit later, but something along those lines should work, so try to fiddle with it as well. \$\endgroup\$Bruno Costa– Bruno Costa2016年05月25日 11:25:29 +00:00Commented May 25, 2016 at 11:25
-
\$\begingroup\$ Thanks a lot for your help man, really appreciate it, but it's not there yet, it also has a weird behavior from what i saw in the fiddle, sometimes the box goes up and down dsh.re/a720d. \$\endgroup\$Valeriu Timbuc– Valeriu Timbuc2016年05月25日 12:47:42 +00:00Commented May 25, 2016 at 12:47
-
\$\begingroup\$ @ValeriuTimbuc Hope that article and this new edit help you better :) \$\endgroup\$Bruno Costa– Bruno Costa2016年05月25日 17:14:28 +00:00Commented May 25, 2016 at 17:14