Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing CSS property with JS mousemove performance

I have a jQuery function changing the background-position property of three elements on mousemove and this seems to be causing some performance issues.

It should be noted that the background images of these elements are SVGs.

Example code:

$(window).on('mousemove', function(event) {
    window.requestAnimationFrame(function() {

        $banner.find('.pattern').each(function(key) {

            var modifier = 20 * (key + 1);

            $(this).css({
                'background-position': (event.pageX / modifier)+'px '+(event.pageY / modifier)+'px'
            });

        });

    });
});

See my working code here: https://codepen.io/thelevicole/project/full/DarVMY/

I am making use of window.requestAnimationFrame() and I also have will-change: background-position; css attribute on each element.

As you can probably tell, this effect is lagging. It seems to get worse on bigger window sizes.

I'm pretty sure the issue is caused by using SVGs for the background images instead of PNGs. The reason I am using SVGs is because of high pixel density screens.

If anyone can give some insight on how I can improve the FPS without having to use PNGs that would be great. Thanks.

like image 207
Levi Cole Avatar asked Nov 08 '22 16:11

Levi Cole


1 Answers

Success. My solution has been a combination of suggestions.

I am now changing the transform property of each element but I ran into another issue while doing this. I have a transform keyframe animation on those same elements and the JS applied styles were being ignored.

To fix this I nested the the keyframe animation elements and used JS to transform the parent.

I have applied the advice from @CristianTraìna to move window.requestAnimationFrame() outside of my mousemove

You can see the update at my original link: https://codepen.io/thelevicole/project/full/DarVMY/

Sadly CodePen doesn't allow for versioning on projects.


Final working code

(function($) {
	'use strict';
	
	var $banner = $('section.interactive');
	if ($banner.length) {
		var $patterns = $banner.find('.pattern');
		
		var x = 0,
			y = 0;
		
		// Bind animation to cursor
		$(window).on('mousemove', function(event) {
			x = event.pageX;
			y = event.pageY;
		});
		
		/**
		 * Tell the browser that we wish to perform an animation
		 * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
		 */
		window.requestAnimationFrame(function animation() {

			// Loop each pattern layer
			$patterns.each(function(key) {

				// Modify the x,y coords per element to give "depth"
				var modifier = 20 * (key + 1);

				// Move background position
				$(this).css({
					'transform': 'translate('+(x / modifier)+'px, '+(y / modifier)+'px)'
				});

			});
			
			window.requestAnimationFrame(animation);

		});
		
		
	}
	
})(jQuery);
section.interactive {
  position: relative;
  height: 100vh;
  background-image: linear-gradient(45deg, #6ac8ea 0%, #5de2c1 100%);
}

section.interactive .layers {
  overflow: hidden;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.15) 0%, transparent 40%, transparent 60%, rgba(0, 0, 0, 0.1) 100%);
}

section.interactive .layers .pattern {
  position: absolute;
  top: -10px;
  left: -10px;
  bottom: -10px;
  right: -10px;
  background-position: top left;
  will-change: background-position;
  background-size: 1000px 1000px;
}

section.interactive .layers .pattern .inner {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}

section.interactive .layers .pattern.pattern-1 .inner {
  background-image: url("http://www.inrialpes.fr/sed/people/boissieux/VEAD/out_Stars.svg");
  filter: blur(2px);
  opacity: 0.3;
  z-index: 1;
  animation: Floating 10s infinite;
  animation-delay: 2s;
  background-size: 800px 800px;
}

section.interactive .layers .pattern.pattern-2 .inner {
  background-image: url("http://www.inrialpes.fr/sed/people/boissieux/VEAD/out_Stars.svg");
  filter: blur(1px);
  opacity: 0.4;
  z-index: 2;
  animation: Floating 10s infinite;
  animation-delay: 1s;
  background-size: 900px 900px;
}

section.interactive .layers .pattern.pattern-3 .inner {
  background-image: url("http://www.inrialpes.fr/sed/people/boissieux/VEAD/out_Stars.svg");
  opacity: 0.4;
  z-index: 3;
  animation: Floating 10s infinite;
  background-size: 1000px 1000px;
}

@keyframes Floating {
  0% {
    transform: translate(-10px, 10px);
  }
  50% {
    transform: translate(10px, -10px);
  }
  100% {
    transform: translate(-10px, 10px);
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Animation performance</title>
	<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css">
	<link rel="stylesheet" href="styles.processed.css">
</head>
<body>
	<section class="interactive">
		<div class="layers">
			<div class="pattern pattern-3">
				<div class="inner"></div>
			</div>
			<div class="pattern pattern-2">
				<div class="inner"></div>
			</div>
			<div class="pattern pattern-1">
				<div class="inner"></div>
			</div>
		</div>
	</section>
	<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</body>
</html>
like image 192
Levi Cole Avatar answered Nov 13 '22 03:11

Levi Cole