Motion Blur Effect with SVG

A tutorial on how to create a motion blur effect on HTML elements using JavaScript and an SVG blur filter.

MotionBlur

View demo Download source

Today we are going to show you how to make a motion blur effect and apply it to regular JS or CSS animations of HTML elements.

Motion blur is a technique widely used in motion graphics and animation in general to make movement seem more smooth and natural.

Motion blur is the apparent streaking of rapidly moving objects in a still image or a sequence of images such as a movie or animation. It results when the image being recorded changes during the recording of a single frame, either due to rapid movement or long exposure.

Motion blur on Wikipedia

In this article, we’ll take a look at how to make an approximation of that effect, for horizontal or vertical transitions.

Attention: Please keep in mind that this effect is highly experimental and only supported by some modern browsers. Chrome seems to have the best performance for it as of now.

In order to apply a motion blur effect to an animation, we need to apply a directional blur to the object according to the speed and direction it is moving, for every frame.

MotionBlur_01

Let’s take a look at the steps we need to take to understand how the effect works:

Setting the blur

Since the regular CSS blur filter does not support directional blur, we are going to have to use SVG filters.
We’ve already covered the basics of SVG filters in the Creative Gooey Effects article.

For this effect, we will only be using the feGaussianBlur filter primitive.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="filters">
	<defs>
		<filter id="blur">
			<feGaussianBlur in="SourceGraphic" stdDeviation="0,0" />
		</filter>
	</defs>
</svg>

The stdDeviation attribute is used to set the blur intensity, and can take up to two parameters, for blur in the horizontal and vertical orientation.

Applying the filter to an element, as we’ve seen before, is simple enough:

.selector{
	-webkit-filter: url("#blur");
	filter: url("../index.html#blur");
}

For the motion blur effect, however, we are going to have to update the filter dynamically for every frame through JS.

First we will have to select and store the filter in a variable so that we can access it later. Since jQuery doesn’t play well with SVG elements, we need to select the element using native JS functions:

var filters = document.querySelector(".filters"), // the SVG that contains the filters
	defs = filters.querySelector("defs"), // the  element inside the SVG
	blur = defs.querySelector("#blur"), // the blur filter
	blurFilter = blur.firstElementChild; // the feGaussianBlur primitive

Setting the intensity then, is just a matter of changing the stdDeviation attribute of the filter primitive. For example, to set a horizontal 12px blur:

blurFilter.setAttribute("stdDeviation","12,0");

MotionBlur_02

Keep in mind that this blur filter only supports directional blur on either the X or the Y direction, and not on any arbitrary angle, so you should plan your animations accordingly.

Note though, that changing the blur filter affects all objects linked to it, so we need a new <filter> element for each object we want to apply this effect to. Here is a simple way of creating these filters dynamically:

// go through all the objects that need a blur filter
$(".js-blur").each(function(i){
	// clone the filter
	var blurClone=blur.cloneNode(true);

	// create and set a new ID so we can use the filter through CSS
	var blurId="blur"+i;
	blurClone.setAttribute("id",blurId);

	defs.appendChild(blurClone);

	// set the CSS
	var filter="url(#"+blurId+")";
	$(this)
		.css({
			webkitFilter:filter,
			filter:filter
		})
		// store the filter reference on the object for practicity
		.data("blur",blurClone)
	;
});

Measuring the speed

For the next step, we need to be able to calculate, how far the object has moved since the last frame. We need to do this for every frame. The method for achieving this might vary according to how everything is set up; how the animation is done, etc. In this tutorial, we’ll take a more generalist approach, which, while it might not be optimized for all use cases, should work with most JS and CSS animations.

To get the position, we’ll be using jQuery’s offset function, which is just what we need: it returns the element’s coordinates relative to the document (rather than its parent), and takes the transform property into account.

To be able to check for changes and update every frame, we’ll use requestAnimationFrame.

Here’s an example:

// the element we want to apply the effect
var $element=$(".selector");
// storing the last position, to be able to measure changes
var lastPos=$element.offset();
// a multiplier, to be able to control the intensity of the effect
var multiplier=0.25;

// a helper to simplify setting the blur. 
function setBlur(x,y){
	blurFilter.setAttribute("stdDeviation",x+","+y);	
}

(function updateMotionBlur(){
	// get the current position of the element
	var currentPos=$element.offset();

	// calculate the changes from the last frame and apply the multiplier
	var xDiff=Math.abs(currentPos.left-lastPos.left)*multiplier;
	var yDiff=Math.abs(currentPos.top-lastPos.top)*multiplier;

	// set the blur
	setBlur(xDiff,yDiff);

	// store current position for the next frame
	lastPos=currentPos;

	// call to update in the next frame
	requestAnimationFrame(updateMotionBlur);
})();

And here is the result:

blur_modal

This is the basic approach which takes only one element into consideration. A more complicated use might require code optimized for it in particular. For a more sophisticated take, you may look into applying the motion blur effect to multiple objects, disabling the blur and the speed calculation when there’s no animation, and so on.

blur_gallery

And we’re done here! Again, with all things filter, please be aware that this effect can be resource intensive, so you should refrain from using it on large objects.

View demo Download source