Vanilla JavaScript Image Magnify π

I'm a full-stack developer from South Africa πΏπ¦. I love writing about JavaScript, HTML and CSS.
Search for a command to run...

I'm a full-stack developer from South Africa πΏπ¦. I love writing about JavaScript, HTML and CSS.
Great work with easy to understand explanations.
However, I wanted to let you know that the Codepen doesn't completely load.
Hey there Nasidul IslamWhat is not loading for you? It seems to work from this side.
Thank you for the very kind words! I also have a daily newsletter which you can subscribe to on my website
Daily Dev Tips Seems to be loading fine now --- wasn't doing so when I tried last time. Keep up the great work !
Most of you know me for my consistency, a golden arrow in my blog series. I've written 1000 articles in 1008 days! Almost an article a day, and my honeymoon was the only holiday I ever took. I'm super proud of this achievement; it has been a fantasti...

It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool. This shows in my previous explorations of Astro, Medusa, and now Vendure as well. All these products thrive in a super open, welcoming, ...

The cool part about Vendure is how easy it is to set up and how abstract each layer is. Basically, we get the following elements: External database Server Worker Admin UI Frontend While this is amazing, it also brings a bit of complexity when it co...

The previous article looked at customizing Vendure on a data and process level. In this article, we'll look at customizing emails, as they are often a big part of a webshop system. We'll be looking at two different layers of customization for customi...

Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case. In this article, I'll take a high-level look at some elements we can customize within...

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.
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%).
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:
Thank you for reading my blog, feel free to subscribe to my email newsletter and connect on Facebook or Twitter