Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix page scroll lag in Chrome

I have been working on a new static website, it's a very simple build but has a few subtle CSS animations, triggered by isInViewport js function.

I have noticed that Chrome renders the page with a small amount of lag on scroll, it's very jarring. Yet in Safari, Firefox it's absolutely fine.

Here is my js for triggering when an element is in viewport.

$.fn.isInViewport = function() {
  var elementTop = $(this).offset().top;
  var elementBottom = elementTop + $(this).outerHeight();

  var viewportTop = $(window).scrollTop();
  var viewportBottom = viewportTop + $(window).height() - 100;

  return elementBottom > viewportTop && elementTop < viewportBottom;
};

$(window).on('resize scroll', function() {
  setTimeout(function(){
    $('section').each(function() {
      if ($(this).isInViewport()) {
        $(this).addClass('reveal');
      }
      else {
      }
    });
   }, 300);
});

Is there anything out of the ordinary I shouldn't be doing?

And here is the CSS relevant to the animation.

.image-reveal {
  position: relative;
  overflow: hidden;
}

.image-reveal-cover {
    background: #fcfcfc;
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: 5;
    transform: translateX(0);
    -webkit-transform: translateX(0);

    transition: transform cubic-bezier(.19, 1, .22, 1) 1.75s;
    -webkit-transition: transform cubic-bezier(.19, 1, .22, 1) 1.75s;
}

.image-reveal img {
  position: relative;
  z-index: 2;
  opacity: 0;
  transform: scale(1.4);
  -webkit-transform: scale(1.4);

  transition: all cubic-bezier(.19, 1, .22, 1) 1.5s;
  -webkit-transition: all cubic-bezier(.19, 1, .22, 1) 1.5s;
}

section.reveal .image-reveal-cover {
  transform: translateX(100%);
  -webkit-transform: translateX(100%);
}

section.reveal .image-reveal img {
  opacity: 1;
  transform: scale(1);
  -webkit-transform: scale(1);
}

Here is a codepen showing an example of the scroll jitteriness in Chrome.

Am I triggering my animations incorrectly? I thought using transform for the base of CSS movement to be relatively lag free?

Any advice is appreciated. Thank you.


Also I am using Chrome 71.0.3578.98 on Mac OS Mojave

like image 420
HeyImArt Avatar asked Jan 18 '19 09:01

HeyImArt


People also ask

How do I fix scroll lag?

For Chrome users, hardware acceleration can be an additional cause of lag. To disable it, click on the three-dot menu in the top-right of your browser, then select Advanced. Click System, then disable hardware acceleration from here. After doing so, you should fix YouTube lagging when you scroll in Chrome.

Why is my screen not scrolling smoothly?

While developers always try their best to make everything run smooth after an upgrade, it's not always the same story on every device. And on most devices, the Android phone scrolling problem is caused by corrupted cache files in the system, bad apps, compatibility issues, software glitches, and others.

Why is there a delay when I type in Chrome?

You might be experiencing slow performance issues with Chrome because it needs to be updated. Within Chrome, go to Settings window and click on Advanced > Reset and clean up. Then, click on Restore settings to their original defaults. Confirm your decision by clicking the Reset settings button in the pop-up window.


2 Answers

For this example i have too much concerns;

  • Get rid of Jquery it is slow and you can do everything with JS (http://youmightnotneedjquery.com/)
  • Why timeout? You don't need it. If you are going to use it kill other timeouts so it will not be duplicated.
  • Use ES6(Easy to understand, read and code) Also you can compile to lower versions. It keeps you updated in your career path.
  • Don't run selectors for each scroll. Use selector before fire scroll.

Here the example:

class ScrollControl {
  constructor() {
    this.sectionDOMList = document.querySelectorAll('section');
    this.initListeners();
  }

  initListeners() {
    window.addEventListener('scroll', (e) => {
      this.animateSections();
    });
  }

  animateSections() {
    for (let i = 0; i < this.sectionDOMList.length; i++) {
      if (this.isInViewport(this.sectionDOMList[i])) {
      	if(!this.sectionDOMList[i].isReveal){
          this.sectionDOMList[i].isReveal = true;
          this.sectionDOMList[i].classList.add('reveal');
        }
      }
    }
  }

  isInViewport(element) {
    const elementCenter = (element.getBoundingClientRect().top + element.getBoundingClientRect().bottom)/2;
    const viewportTop = window.scrollY;
    const viewportBottom = viewportTop + window.innerHeight;
    return elementCenter < viewportBottom;
  }
}

(function() {
  new ScrollControl();
})();
/* Reset */

html {
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 16px;
}

*,
*:before,
*:after {
  -webkit-box-sizing: inherit;
  box-sizing: inherit;
}

body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
ol,
ul {
  margin: 0;
  padding: 0;
  font-weight: normal;
}

ol,
ul {
  list-style: none;
}

img {
  max-width: 100%;
  height: auto;
}

/* Base */

body {
  width: 100%;
  height: 100%;
  background: white;
  color: #3b3b3b;
  font-family: 'Larsseit', Helvetica, Arial, sans-serif;
}

.container {
  max-width: 1640px;
  margin-left: 30px;
  margin-right: 30px;
}

@media (min-width: 768px) {
  .container {
    margin-left: 80px;
    margin-right: 80px;
  }
}

@media (min-width: 1800px) {
  .container {
    margin: 0 auto;
  }
}

.vc {
  display: table;
  height: 100%;
}

.vc-ele {
  display: table-cell;
  vertical-align: middle;
}

section {
  padding: 400px 0;
}

section.full-vh {
  position: relative;
  width: 100%;
  height: 100vh;
  padding: 0;
}

.row {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

.col-half {
  width: 100%;
}

@media (min-width: 992px) {
  .col-half {
    width: 50%;
  }
}

.row.align-center {
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
}

/* Typography */

h1 {
  font-size: 52px;
}

h2 {
  font-size: 26px;
}

p {
  font-family: 'Larsseit', Helvetica, Arial, sans-serif;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.5;
  color: #3b3b3b;
}

/* Image reveal */

.image-reveal {
  position: relative;
  overflow: hidden;
}

.image-reveal-cover {
  background: #fcfcfc;
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 5;
  transform: translateX(0);
  -webkit-transform: translateX(0);
  transition: transform cubic-bezier(.19, 1, .22, 1) 1.75s;
  -webkit-transition: transform cubic-bezier(.19, 1, .22, 1) 1.75s;
}

.image-reveal img {
  position: relative;
  z-index: 2;
  opacity: 0;
  transform: scale(1.4);
  -webkit-transform: scale(1.4);
  transition: all cubic-bezier(.19, 1, .22, 1) 1.5s;
  -webkit-transition: all cubic-bezier(.19, 1, .22, 1) 1.5s;
}

section.reveal .image-reveal-cover {
  transform: translateX(100%);
  -webkit-transform: translateX(100%);
}

section.reveal .image-reveal img {
  opacity: 1;
  transform: scale(1);
  -webkit-transform: scale(1);
}
<div id="page">
  <div class="container">

    <section class="full-vh">
      <div class="vc">
        <div class="vc-ele">
          <h1>Scroll down</h1>
        </div>
      </div>
    </section>

    <section>
      <div class="row align-center">

        <div class="col-half">
          <div class="image-reveal">
            <div class="image-reveal-cover"></div>
            <img src="https://fearthewild.com/clients/playground/horse.jpg" alt="Horse" />
          </div>
        </div>

        <div class="col-half">
          <h2>This is my horse.</h2>
          <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem
            quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</p>
          <p>Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem
            ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
        </div>

      </div>
    </section>

  </div>
</div>
like image 158
hurricane Avatar answered Oct 18 '22 00:10

hurricane


Don't listen to scroll (or resize) events and then calculate if elements are in viewport, rather use Intersection Observer (IO) for this.

IO observers one (or multiple) elements and reacts if they intersect either with each other or with the viewport.

First, you have to specify your options for your IO:

let options = {
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

In your case you need to test for intersecting with window, so no root value needs to specified for options. We also specify that a function named callback is getting executed whenever the IO is getting triggered.

Next step is to define the elements that should be observed, in your case these would be section elements:

let targets = document.querySelectorAll('section');
targets.forEach(target => {
  observer.observe(target);
});

Now everything is set up, all that's left to do is to define what should actually happen in the callback function:

let callback = (entries, observer) => { 
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element
    // I think you are be interested in entry.isIntersecting check. 
  });
};

Also check this example on how to change background color based on how much the box is visible in the viewport.

You can also use this polyfill from w3c to support older browsers.

like image 2
cloned Avatar answered Oct 18 '22 02:10

cloned