Vanilla JavaScript Image Magnify 🔎

— 11 minute read

This one, for me, is a typical function where people used to relax and rely on plugins. But join me, and I'll show you how easy it is to create a hover magnify function in Vanilla JavaScript.

HTML Setup permalink

As always lets start with the HTML structure

<div class="container">
<div id="zoom" class="magnify-wrapper">
<img
src="https://images.unsplash.com/photo-1542856204-00101eb6def4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=975&q=80"
id="main-img"
/>

<div id="large-img"></div>
</div>
</div>

We use the container to perfectly center our element.

Then we have a magnify-wrapper, which will act as our hover div, so once we hover this div, the magnifying glass will show a bigger version of the image.

Then we add the image and a ghost div in which we will load the large image.

CSS Structure for a Magnify Effect

.magnify-wrapper {
position: relative;
max-height: 50vh;
}
.magnify-wrapper img {
max-height: inherit;
}
.magnify-wrapper #large-img {
background: url('https://images.unsplash.com/photo-1542856204-00101eb6def4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=975&q=80')
no-repeat #fff;
width: 100px;
height: 100px;
box-shadow: 0 5px 10px -2px rgba(0, 0, 0, 0.3);
pointer-events: none;
position: absolute;
border: 4px solid #efefef;
z-index: 99;
border-radius: 100%;
display: block;
opacity: 0;
transition: opacity 0.2s;
}
.magnify-wrapper:hover #large-img,
.magnify-wrapper:active #large-img
{
opacity: 1;
}

Lets go through each element in detail:

.magnify-wrapper {
position: relative;
max-height: 50vh;
}

We make sure the wrapper is relative because our magnify glass is going to be absolute position based on this element. Then we make it only 50% of our viewport height. You can read all about viewport units here.

.magnify-wrapper img {
max-height: inherit;
}

For the image we see we tell it to be also 50% of the viewport by inheriting the height from our wrapper.

.magnify-wrapper #large-img {
background: url('https://images.unsplash.com/photo-1542856204-00101eb6def4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=975&q=80')
no-repeat #fff;
width: 100px;
height: 100px;
box-shadow: 0 5px 10px -2px rgba(0, 0, 0, 0.3);
pointer-events: none;
position: absolute;
border: 4px solid #efefef;
z-index: 99;
border-radius: 100%;
display: block;
opacity: 0;
transition: opacity 0.2s;
}

Now bear with me, for the large image div we set it to have the same image as a background-image with no-repeat. Then we make it show as a 100px by 100px box, and add a small box-shadow to give it some depth. Then like mentioned we position: absolute it so it can float on top of our wrapper. And add a border to make it visual appealing. Then we make it round by doing: border-radius: 100%. And we make it completely invisible by setting opacity: 0 and added an animation on the opacity to make it fade-in.

.magnify-wrapper:hover #large-img,
.magnify-wrapper:active #large-img
{
opacity: 1;
}

This is the last element to our CSS and we tell the code if we hover our wrapper of it's active we must make the opacity of our large image div 1 (100%).

Vanilla JavaScript to make our Magnify hover work permalink

document.getElementById('zoom').addEventListener(
'mousemove',
function(e) {
var original = document.getElementById('main-img'),
magnified = document.getElementById('large-img'),
style = magnified.style,
x = e.pageX - this.offsetLeft,
y = e.pageY - this.offsetTop,
imgWidth = original.width,
imgHeight = original.height,
xperc = (x / imgWidth) * 100,
yperc = (y / imgHeight) * 100;

// Add some margin for right edge
if (x > 0.01 * imgWidth) {
xperc += 0.15 * xperc;
}

// Add some margin for bottom edge
if (y >= 0.01 * imgHeight) {
yperc += 0.15 * yperc;
}

// Set the background of the magnified image horizontal
style.backgroundPositionX = xperc - 9 + '%';
// Set the background of the magnified image vertical
style.backgroundPositionY = yperc - 9 + '%';

// Move the magnifying glass with the mouse movement.
style.left = x - 50 + 'px';
style.top = y - 50 + 'px';
},
false
);

Let's make it more readable section by section:

document.getElementById('zoom').addEventListener('mousemove', function(e) {}, false);

This code adds a eventListener to the element with the id zoom and will fire every time the mousemove event happens on it.

var original = document.getElementById('main-img'),
magnified = document.getElementById('large-img'),
style = magnified.style,
x = e.pageX - this.offsetLeft,
y = e.pageY - this.offsetTop,
imgWidth = original.width,
imgHeight = original.height,
xperc = (x / imgWidth) * 100,
yperc = (y / imgHeight) * 100;

We then define all our variables in one go. We start by selecting the original image which is the div with the id main-img and the magnified div which has id large-img. Then we get the entry point of the mouse by calculating the page position minus the offset on the element. Then we get the original image size and calculate the percentage where our mouse is.

// Add some margin for right edge
if (x > 0.01 * imgWidth) {
xperc += 0.15 * xperc;
}

// Add some margin for bottom edge
if (y >= 0.01 * imgHeight) {
yperc += 0.15 * yperc;
}

We added these 2 calculations to add some overflow on the right side and the bottom. This is needed because our hover is bigger than the image so it must be fixed with above code.

// Set the background of the magnified image horizontal
style.backgroundPositionX = xperc - 9 + '%';
// Set the background of the magnified image vertical
style.backgroundPositionY = yperc - 9 + '%';

// Move the magnifying glass with the mouse movement.
style.left = x - 50 + 'px';
style.top = y - 50 + 'px';

This is the actual magic in the whole script; it's what makes things move; we make the background-image position based on the percentage of our mouse position. Then we move this div based on the actual mouse position.

You can see this in action on the following Codepen:

See the Pen Vanilla JavaScript Image Magnify 🔎 by Chris Bongers (@rebelchris) on CodePen.

Thank you for reading, and let's connect! permalink

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter