Smoothing the parallax scrolling of a background image
Asked Answered
W

6

12

I've done a bit of research and written a simple bit of jQuery that scrolls the background at a slightly different pace to the foreground, creating a parallaxing effect as you scroll down a website.

Unfortunately it's a bit jerky.

Here's the basic layout of the HMTL:

<body>
    <section>
        Site content goes here.
    </section>
</body>

Here's the CSS:

body {
    background-image: url('../images/bg.png');
    background-repeat: repeat-y;
    background-position: 50% 0;    
}

Here's the JS:

$(window).scroll(function () {
    $("body").css("background-position","50% " + ($(this).scrollTop() / 2) + "px");
});

https://jsfiddle.net/JohnnyWalkerDesign/ksw5a0Lp/

Pretty simple, but my problem is that it's a bit jerky when you scroll, even on a powerful computer.

Is there a way to make the background parallax animate smoothly?

Wallraff answered 3/4, 2013 at 13:42 Comment(1)
Hey, check this blog post about parallax: html5rocks.com/en/tutorials/speed/parallaxSanatory
B
16

Add transition property to your CSS so it can be accelerated by the GPU like this:

body {
    background-image: url('../images/bg.png');
    background-repeat: repeat-y;
    background-position: 50% 0;    
    transition: 0s linear;
    transition-property: background-position;
}
Bakemeier answered 4/6, 2014 at 14:12 Comment(3)
The difference is minor, but this is what I went forWallraff
0s? Shouldn't be it something like 0.5s?Lavine
i dont think so. wouldn't that delay the effect, and have the background you want unmoving, moving slightly on scroll?Bakemeier
W
7

Try animating a property that can be hardware accelerated in browsers that support it. Rather than changing the background-position property, use an absolutely positioned img and then change its position using CSS transforms.

Take a look at stellar.js. That plugin gives you the option of animating using CSS transforms in capable browsers (stellar.js will let you animate background images, with the caveat that it won't work as smoothly on mobile devices). It also makes use of requestAnimationFrame, meaning less CPU, GPU, and memory usage.

If you deem a plugin overkill, you can at least check out the approach taken and adapt it to your needs.

Weakly answered 3/4, 2013 at 13:55 Comment(0)
D
5

Set the css of the body as below:

body {
  background-image: url(images/bg.jpg); 
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-position: 0 0;
 }

Then using Javascript just get the pageYOffset on page scrolling, and set it to background position of the body background image as below:

window.addEventListener('scroll', doParallax);
function doParallax(){
   var positionY = window.pageYOffset/2;
   document.body.style.backgroundPosition = "0 -" + positionY + "px";
}

Just checkout my post here: http://learnjavascripteasily.blogspot.in/

Duma answered 16/2, 2016 at 5:18 Comment(2)
I am trying to use this on a class: document.getElementsByClassName("parallax").style.backgroundPosition = "0 -" + positionY + "px"; but it is not working. Any tip?Sedgewake
document.getElementsByClassName("parallax") will give you an array of dom elements. You cannot directly use 'style' property directly on array of elements. So try using 'document.getElementsByClassName("parallax")[0].style.background‌​Position', if there's only one element having class 'parallax'Duma
G
2

Sometimes we can not use a <img> element inside a div for some reasons like a border-radius may stop working or a width bigger the than parent. I was facing all these issues and the best solution I found was to use:

transition: 0.5s ease;
transform: translate3d(0, 0, 0);

I got really nice and smooth parallax effect using GPU.

Ginetteginevra answered 21/7, 2014 at 21:1 Comment(1)
Not a bad look.Wallraff
J
1

To make it smooth put the image on a separate div and move the whole element using transform: translate - then you will get really smooth results.

Here is a little example doing something a little bit different but using translate to give you the idea:

HTML:

<div id="wrapper">
     <div id="content">Foreground content</div>
</div>

CSS:

@-webkit-keyframes MOVE-BG {
    0% {
        transform: translate(0%, 0%);
        -webkit-transform: translate(0%, 0%);
    }
    50% { 
        transform: translate(-250px, 0%);
        -webkit-transform: translate(-250px, 0%);
    }
    100% {
        transform: translate(0%, 0%);
        -webkit-transform: translate(0%, 0%);
    }
}

#wrapper {
    width: 300px;
    height: 368px;
    overflow: hidden;  
}
#content {
    width: 550px;
    height: 368px;
    background: url(http://www.gstatic.com/webp/gallery/1.jpg) 0% 0% repeat;
    text-align: center;
    font-size: 26px;
    color: #000;

    -webkit-animation-name: MOVE-BG;
    -webkit-animation-duration: 10s;
    -webkit-animation-timing-function: linear;
    -webkit-animation-iteration-count: infinite;
}

and the fiddle: http://jsfiddle.net/piotku/kbqsLjfL/

from within javascript (using jQuery) you would have to use something like:

$(".element").css("transform", 'translateY(' + ($(this).scrollTop() / 2) + 'px)');

or in vanillaJS:

backgroundElement.style.transform = 'translateY(' + ($(this).scrollTop() / 2) + 'px)';
Jehad answered 29/3, 2017 at 6:25 Comment(5)
I don't think this will work as well as you imagine. Try putting it into a fiddle (not just the transform you've posted) and I think you'll see it will behave oddly.Wallraff
Also, odd use of prefixes. Probably best to avoid using them these days, and relying on Autoprefixer instead.Wallraff
@Chuck Le Butt there is a fiddle link in the answer :) and you're right about the prefixes - I was just quickly creating a working exampleJehad
Yes, as I said, your fiddle link doesn't really demonstrate the solution to the problem. It's just a basic transform, which I'm not sure will work in a parallax situation, but maybe you could demonstrate it in a fiddle. Also, I see you've adapted code from this question (#21088018), which is probably why it's got so many quirks. Thanks for trying.Wallraff
Huh! I made my own fiddle and it works pretty nicely actually! jsfiddle.net/JohnnyWalkerDesign/ra90axjqWallraff
I
0

Try changing the .css to .animate. so instead of setting the CSS to hard values you can animate it.

$(window).scroll(function () {
    $("body").animate({"background-position":"50% " + ($(this).scrollTop() / 2) + "px"},{queue:false, duration:500});
});

NB: add script http://snook.ca/technical/jquery-bg/jquery.bgpos.js

Please keep in mind I haven't tested it, let me know if it works.

Animate Background images : http://snook.ca/archives/javascript/jquery-bg-image-animations

Demo: http://snook.ca/technical/jquery-bg/

Intersex answered 3/4, 2013 at 13:55 Comment(6)
In general, the jQuery animate() function can't be used on a multi-part value like background-position. The individual background-position-x and background-position-y styles have not been standardized and don't appear to be supported by all browsers.Nobby
Yes, and how would a parallax site run in IE6? Not very good I can imagine.Intersex
background-position-x and background-position-y are not supported by the latest versions of Firefox and Opera. They were dropped from the CSS3 spec. It's uncertain whether they'll be in the CSS4 spec. As currently written, the above code doesn't work in any browser.Nobby
Thanks for the info! And this won't be supported at all?Intersex
@MarcUberstein Ha! I don't plan on supporting IE6 in this day and age anyway :)Wallraff
@DjangoReinhardt Remember to add the script snook.ca/technical/jquery-bg/jquery.bgpos.js - see updated answer.Intersex

© 2022 - 2024 — McMap. All rights reserved.