This article may contain affiliate links. If you buy some products using those links, I may receive monetary benefits. See affiliate disclosure here
There are certain visual effects in web design which can give a luxurious feel to your site when used appropriately. In this article, we are going to do such an effect.
What we are going to build
Recently, while browsing for modern UI trends, I came across a couple of sites whose homepages boast a blurred image which doesn’t look like a big deal at first. But when you hover over the image, you can see the real sharp image in an area around the mouse pointer.
I felt it was very nice and engaging especially for artistic websites. So I dug a little to know how it was done and soon found out that they are using the power of HTML5 SVG (Scalable Vector Graphics) for it.
Demo
See on CodePen: https://codepen.io/iabhinavr/pen/ZEWjzde
Basically, we will be using the following to recreate it:
- HTML5 SVG element
- Gaussian Blur Filter
- SVG Masking
- Javascript Event Listeners
HTML Markup
Our initial HTML markup is very basic with just an outer wrapper and an inner container for our SVG element;
index.html
<!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>Blur Effect - HTML5 SVG</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="svg-wrapper">
<div class="svg-in">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" id="imagesvg">
<filter id="blur-image">
<feGaussianBlur in="SourceGraphic" stdDeviation="20"></feGaussianBlur>
</filter>
<mask id="blur-mask">
<circle cx="100" cy="100" r="50" fill="#555555" id="mask-circle"></circle>
</mask>
<image xlink:href="images/photo-1.jpeg" width="100%" height="100%" filter="url(#blur-image)" />
<image xlink:href="images/photo-1.jpeg" width="100%" height="100%" mask="url(#blur-mask)" />
</svg>
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
Now let us look at the SVG element in detail:
The SVG element includes three main parts:
1. Gaussian Blur Filter
<filter id="blur-image">
<feGaussianBlur in="SourceGraphic" stdDeviation="20"></feGaussianBlur>
</filter>
The filter tag defines a Gaussian Blur with stdDeviation attribute set to 20. The higher the value of stdDeviation, the higher the blurring effect.
2. SVG Mask
<mask id="blur-mask">
<circle cx="100" cy="100" r="50" fill="white" opacity="1" id="mask-circle"></circle>
</mask>
This element defines a circle with white fill-color, radius 50 and offset 100. When the mask is applied to an element, this shape, and its fill-color determines what part of the element will be visible and by how much. So white fill is fully visible while black is invisible. Anything in between (like #555555) gives a semi-transparent mask.
3. and, the images
<image xlink:href="images/photo-1.jpeg" width="100%" height="100%" filter="url(#blur-image)" />
<image xlink:href="images/photo-1.jpeg" width="100%" height="100%" mask="url(#blur-mask)" />
We add the same image two times, one on top of the other.
Using the filter attribute to apply the blur to the bottom layer.
Then apply the mask on the top layer using the mask attribute. This makes the top image (non-blurred image) invisible except the area below the white circle.
Here is the complete tag:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" id="imagesvg">
<filter id="blur-image">
<feGaussianBlur in="SourceGraphic" stdDeviation="20"></feGaussianBlur>
</filter>
<mask id="blur-mask">
<circle cx="100" cy="100" r="50" fill="white" opacity="1" id="mask-circle"></circle>
</mask>
<image xlink:href="images/photo-1.jpeg" width="100%" height="100%" filter="url(#blur-image)" />
<image xlink:href="images/photo-1.jpeg" width="100%" height="100%" mask="url(#blur-mask)" />
</svg>
Stylesheet
style.css
.svg-wrapper {
position: relative;
width: 100%;
height: 0;
padding-bottom: 66%;
}
.svg-in {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
The class .svg-wrapper is for maintaining the aspect ratio of the image we are using. The inner .svg-in has absolute positioning offsets set to zero, so it occuppies the entire area of its parent.
The Javascript
main.js
(function(){
var svg = document.getElementById('imagesvg');
var maskCircle;
var svgX, svgY, maskX, maskY;
function updateMask(event) {
var pointerX = event.clientX;
var pointerY = event.clientY;
svgX = svg.getBoundingClientRect().left;
svgY = svg.getBoundingClientRect().top;
maskX = pointerX - svgX;
maskY = pointerY - svgY;
maskCircle.setAttribute('cx', maskX);
maskCircle.setAttribute('cy', maskY);
}
if (svg) {
maskCircle = document.getElementById('mask-circle');
svg.addEventListener('mousemove', updateMask);
}
})();
The event listener calls the updateMask function whenever the mouse pointer moves over the SVG element.
The updateMask function finds the mouse position and element position relative to the window and calculates the x and y values relative to the element. Finally, we set the cx and cy attributes of the masking circle to these values. So that is how the circle follows the mouse pointer.
Using this idea we can create several interesting variations of this effect. Let us look at those later. If you find this useful, or if you have used such an effect in your projects, say about it in the comments.