Levi Cole Levi Cole - 8 months ago 94
CSS Question

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.

Answer Source

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>

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download