Creating an Image Zoom Library With Vanilla JavaScript

Demo Download

In this tutorial we are going to build a simple JavaScript library for adding zoom-on-hover effects to images. We will make the whole library from scratch, without relying on jQuery or any other external dependencies. Let's jump right in!

The Project

You can see this type of effect on many shopping sites, including very popular ones like eBay and Amazon. It usually consists of a group of small photos which can be enlarged and inspected in further detail with an on-hover magnifier.

Our Library in Action

To keep the tutorial simple we won't be adding too many features to the library. It will contain only one JavaScript file, plus an optional CSS file for quickly styling a gallery like the one above.

Designing the Library

Before we start building the library, let's take a look at how we want people to use it. Making that design decision first will make developing the actual library easier later on.

Since we are making a gallery plugin, people who use it will need to have some boilerplate HTML. This markup will contain their images, an empty div for the zoom effect, as well as some predefined classes to make the library work.

<div id="my-gallery" class="vanilla-zoom">
    <div class="sidebar">
        <img src="images/image-1.jpg" class="small-preview">
        <img src="images/image-2.jpg" class="small-preview">
        <img src="images/image-3.jpg" class="small-preview">
    </div>
    <div class="zoomed-image"></div>
</div>

People are free to change this layout and add as many images as they want. It's important, however, that every image has the .small-preview class, and that there is an empty div with the .zoomed-image class.

The library will be mainly JavaScript driven but there are also a few important CSS styles that need to be set. Users can include our CSS file directly in their HTML.

<link rel="stylesheet" href="vanilla-zoom/vanilla-zoom.css">

Now that the markup and styles are set, all that is left is to include the library and initialize it.

<script src="vanilla-zoom/vanilla-zoom.js"></script>
<script>
    vanillaZoom.init('#my-gallery');
</script>

Including the library's .js file makes the vanillaZoom object globally available. The object has only one method which is for initializing the plugin. It takes a single parameter - the id of our gallery. This way we can have multiple independent galleries initialized on one page.

Developing the Library

When building front-end JavaScript libraries we need to make sure we register their API properly. There are many ways to do this, possibly the easiest of which is this method by Jordan Checkman. We advise you to read his full blog post, but in short it boils down to this:

(function(window) {
  function define_library() {
    // Create the library object and all its properties and methods.
    var vanillaZoom = {};
    vanillaZoom.init = function(galleryId) {
      // Our library's logic goes here.
    }
    return vanillaZoom;
  }

  // Add the vanillaZoom object to global scope if its not already defined.
  if(typeof(vanillaZoom) === 'undefined') {
    window.vanillaZoom = define_library();
  }
  else{
    console.log("Library already defined.");
  }
})(window);

The above code is wrapped in a self executing function. This way when we add the vanilla-zoom.js file to our project, the library will be automatically registered and the vanillaZoom object with all its methods will be made available to the user.

Our library has only one method - vanillaZoom.init(galleryId). Its job is to select the gallery DOM elements and add event listeners to them.

First we check if the proper elements have been added to the HTML and select them. We can't use jQuery so we have to rely on the native JavaScript methods for working with the DOM.

var container = document.querySelector(el);

if(!container) {
    console.error('Please specify the correct class of your gallery.');
    return;
}

var firstSmallImage = container.querySelector('.small-preview');
var zoomedImage = container.querySelector('.zoomed-image');

if(!zoomedImage) {
    console.error('Please add a .zoomed-image element to your gallery.');
    return;
}

if(!firstSmallImage) {
    console.error('Please add images with the .small-preview class to your gallery.');
    return;
}
else {
    // Set the source of the zoomed image.
    zoomedImage.style.backgroundImage = 'url('+ firstSmallImage.src +')';
}

In the last line of the above code we take the image source of one of the preview images and set it as the background of our zoomable element. This happens as soon as vanillaZoom.init(galleryId) is called, making sure that our gallery doesn't stay empty.

We do the same when one of the previews is clicked. This allows the user to select which image they want magnified.

container.addEventListener("click", function (event) {
  var elem = event.target;

  if (elem.classList.contains("small-preview")) {
      zoomedImage.style.backgroundImage = 'url('+ elem.src +')';
  }
});
Selecting Images

The magnifier element has a couple of event listeners attached to it. The first one is activated when the cursor enters the element, increasing the size of the background image, thus creating a zoom effect.

zoomedImage.addEventListener('mouseenter', function(e) {
    this.style.backgroundSize = "250%"; 
}, false);

Since the image is now very large, it won't fit in the container and only part of it will be visible. We want users to be able to select which portion of the image is magnified so we add a mousemove listener that changes the background position.

zoomedImage.addEventListener('mousemove', function(e) {

  // getBoundingClientReact gives us various information about the position of the element.
  var dimentions = this.getBoundingClientRect();

  // Calculate the position of the cursor inside the element (in pixels).
  var x = e.clientX - dimentions.left;
  var y = e.clientY - dimentions.top;

  // Calculate the position of the cursor as a percentage of the total size of the element.
  var xpercent = Math.round(100 / (dimentions.width / x));
  var ypercent = Math.round(100 / (dimentions.height / y));

  // Update the background position of the image.
  this.style.backgroundPosition = xpercent+'% ' + ypercent+'%';

}, false);
Magnifying Specific Part of Image

When the cursor leaves the magnified image we want it to go back to normal. This is easily done by returning the background size to cover and the background position to center.

zoomedImage.addEventListener('mouseleave', function(e) {
    this.style.backgroundSize = "cover"; 
    this.style.backgroundPosition = "center"; 
}, false);

And with that, we are done!

Browser Support

The library should work in all modern desktop browsers, although some of the flexbox CSS may not be displayed properly on older IE.

Sadly, the zoom effect doesn't translate very well to touch devises. Because of this and the limited screen space, it's best to present your images in another way for mobile. In our CSS we've simply hidden the zoom element and listed the images vertically but you can try other solutions such as a carousel.

Conclusion

You can get the full source code for this article, as well as the demo code (with images courtesy to Burst), from the Download button near the top of the page. You are free to use the library in all your projects, commercial or personal (our license). Happy coding!

Presenting Bootstrap Studio

a revolutionary tool that developers and designers use to create
beautiful interfaces using the Bootstrap Framework.

Learn more
Web Browser Frame DevKit Box Mouse Cursor

Related Articles

Comments 6