Search code examples
javascriptfirefoxscrollsafariparallax

Parallax scroll choppy performance on Safari & Firefox


I'm building a onepager with a parallax intro. For the parallax effect I'm using the following piece of JS:

// Parallax
var layerBg = document.querySelector('.js-layer-bg');
var layerText = document.querySelector('.js-layer-text');
var sectionIntro = document.getElementById('section-intro');
var scrollPos = window.pageYOffset;
var layers = document.querySelectorAll('[data-type=\'parallax\']');

var parallax = function() {
  for (var i = 0, len = layers.length; i < len; i++) {
    var layer = layers[i];
    var depth = layer.getAttribute('data-depth');
    var movement = (scrollPos * depth) * -1;
    var translate3d = 'translate3d(0, ' + movement + 'px, 0)';

    layer.style['-webkit-transform'] = translate3d;
    layer.style.transform = translate3d;
  }
};

window.requestAnimationFrame(parallax);

window.addEventListener('scroll', function() {

  // Parallax layers
  scrollPos = window.pageYOffset;
  window.requestAnimationFrame(parallax);

  // Animate text layers
  var vhScrolled = Math.round(window.pageYOffset / window.innerHeight * 100);
  if (vhScrolled > 100 && layerText.classList.contains('is-hidden')) {
    layerText.classList.remove('is-hidden');
  } else if (vhScrolled <= 100 && !layerText.classList.contains('is-hidden')) {
    layerText.classList.add('is-hidden');
  }
});

Apart from this I'm animating a few other things on scroll using 2 libraries: ScrollMonitor and ScrollReveal. Nothing too special.

I've been developing this on Chrome and everything seems to be working smoothly enough. However, when I tested on Safari and especially Firefox, things got so laggy to the point of actually crashing my browser.

I really can't figure out what I am doing wrong and why performance is so different between browsers.

Hopefully you can help me out, thanks!


Solution

  • I'm not altogether certain about what's specifically causing the lag/choppiness issues, I seem to remember something similar in past projects. I'd look into any further image optimization to lower the weight of what's being rendered, that can make a huge difference. Otherwise, I've made a few suggestions for efficiency tweaks that might help it run a bit faster:

    // Parallax
    var layerBg = document.querySelector('.js-layer-bg');
    var layerText = document.querySelector('.js-layer-text');
    var sectionIntro = document.getElementById('section-intro');
    var layers = document.querySelectorAll('[data-type=\'parallax\']');
    var len = layers.length; // cache length
    var layerarray = []; //create cache for depth attributes
    
    var i = -1;
    while(++i < len){
      layerarray.push([layers[i], parseInt(layers[i].getAttribute('data-depth'))]); //create an array that stores each element alongside its depth attribute instead of requesting that attribute every time
    }
    
    var parallax = function() {
      var scrollPos = window.pageYOffset; //define inside function instead of globally
      var i = -1;
    
      while(++i < len) { //while loop with cached length for minor speed gains
        var layer = layerarray[i][0];
        var depth = layerarray[i][1];
        var movement = (scrollPos * depth) * -1;
        var translate3d = ['translate3d(0, ', movement, 'px, 0)'].join(""); //join statement is much faster than string concatenation
    
        layer.style['-webkit-transform'] = translate3d;
        layer.style.transform = translate3d;
      }
    
    
      // Animate text layers
      var vhScrolled = Math.round(scrollPos / window.innerHeight * 100);
      if (vhScrolled > 100 && layerText.classList.contains('is-hidden')) {
        layerText.classList.remove('is-hidden');
      } else if (vhScrolled <= 100 && !layerText.classList.contains('is-hidden')) {
        layerText.classList.add('is-hidden');
      }
    };
    
    window.requestAnimationFrame(parallax);
    
    window.addEventListener('scroll', function() {
    
      // Parallax layers
      window.requestAnimationFrame(parallax);
    
      //moved text animation into the animationframe request
    });