webdevpuneet.com

Product Image Magnify Lens — Free HTML CSS JS Amazon-Style Zoom Snippet

Product Image Magnify Lens · Media · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="magnify-wrap">
  <div class="image-panel" id="imagePanel">
    <div class="product-image" id="productImage"></div>
    <div class="lens" id="lens"></div>
  </div>
  <div class="zoom-panel" id="zoomPanel">
    <p class="zoom-hint">Hover the image to zoom</p>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Lens square tracks the cursor precisely using getBoundingClientRect-relative coordinates
Lens position is clamped so it can never slide past the edges of the source image
Zoomed panel uses a scaled background-image with matching background-position math, sprite-sheet style
Single ZOOM_FACTOR constant keeps the lens size and the zoom scale mathematically in sync
Zoom panel and lens only activate on mouseenter/mousemove, resetting cleanly on mouseleave
No canvas or WebGL required — pure CSS background-image transforms
Works with any image source once background-image is set on the product image element
Adjustable lens size and zoom factor via two independent, clearly-named values

About this UI Snippet

Product Image Magnify Lens — HTML, CSS & JavaScript Hover Zoom

Screenshot of the Product Image Magnify Lens snippet rendered live

E-commerce product pages often need to show fine detail — fabric texture, stitching, screen resolution — that a normal-sized photo can't convey. The "magnify lens" pattern, popularized by Amazon, solves this by overlaying a small square lens on the image that follows the cursor, while a separate zoomed panel shows a magnified view of exactly the region under the lens.

How the lens follows the cursor

A mousemove listener on the image container calculates the cursor's position relative to the container using e.clientX - rect.left and e.clientY - rect.top (where rect is from getBoundingClientRect()). The lens is centered on the cursor by subtracting half its own size from that position. Math.max(0, Math.min(...)) clamps the lens position so it never slides past the edges of the image — without this clamp, dragging the cursor to the very edge would push the lens partially outside the image bounds, which looks broken and would reference invalid image coordinates.

How the zoomed panel shows the correct region

The zoom panel is a separate element with its own background-image set to the *same* image as the product photo, but scaled much larger via background-size (the container's width/height multiplied by a ZOOM_FACTOR), and then positioned with background-position set to the negative of the lens's coordinates, also multiplied by ZOOM_FACTOR. This is the same technique used by CSS sprite sheets: an oversized background image is shifted so only the desired region shows through the panel's fixed viewport size. Because the lens position and the background-position math both derive from the same x/y values (just scaled by the zoom factor), the zoomed view always shows precisely what's under the lens, not an approximation.

Why the zoom factor is a single constant

ZOOM_FACTOR controls both how much larger the background image is scaled and how much further the background-position shifts per pixel of lens movement — these two numbers must always match, or the zoomed image would drift out of alignment with the lens as the cursor moves. Keeping it as one shared constant guarantees they never get out of sync.

Extending to real photography

This demo uses a repeating CSS gradient as a stand-in "image" so the effect is visible without an external asset. In production, set background-image: url(...) on .product-image with a real, sufficiently high-resolution photo — the zoom quality is limited by the source image's native resolution, since the zoom panel is just scaling that same file larger.

Step by step

How to Use

  1. 1
    Load the snippetClick "Product Image Magnify Lens" in the sidebar Library tab to load the demo panels.
  2. 2
    Hover the imageMove your cursor over the left panel in the preview and watch the lens follow it and the right panel zoom in.
  3. 3
    Swap in a real photoReplace the .product-image background gradient with background-image: url(your-photo.jpg) at high resolution.
  4. 4
    Adjust the zoom levelChange the ZOOM_FACTOR constant in the JS panel — higher values zoom in further but require a higher-resolution source image.
  5. 5
    Adjust the lens sizeChange the lens width/height in the CSS panel to make the highlighted region larger or smaller.
  6. 6
    Export and saveExport as HTML/JSX/Tailwind or click "Save as" to reuse this on a real product detail page.

Real-world uses

Common Use Cases

SHOP
E-commerce product detail pages
Let shoppers inspect fine texture, stitching, or material detail before purchasing, exactly like major retail sites.
Art and photography portfolios
Allow viewers to zoom into brushwork or fine photographic detail without opening a separate lightbox.
Learn coordinate-mapped zoom mechanics
Study how lens position and background-position math must scale together by the same factor to stay aligned.
Real estate and interior photography
Adapt the pattern to let buyers inspect finishes, fixtures, or floor materials in listing photos up close.
Foundation for pinch-zoom on mobile
Use as a base to add a touch-equivalent pinch-to-zoom interaction for mobile shoppers.
Related: Accordion — CSS Only Checkbox Hack (No JavaScript)
See the Accordion — CSS Only Checkbox Hack (No JavaScript) for a related misc pattern worth pairing with this one.
Related: Sticky Add to Cart Bar
See the Sticky Add to Cart Bar for a related misc pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

A mousemove listener uses getBoundingClientRect() on the image container to get its position on the page, then subtracts that from the cursor's clientX/clientY to get coordinates relative to the image itself, independent of scroll position or page layout.

The zoom panel shares the same background image as the product photo, scaled up by a zoom factor via background-size, and shifted into position with background-position set to the negative of the lens coordinates multiplied by that same zoom factor — the same technique used for CSS sprite sheets.

They aren't directly coupled by value, but ZOOM_FACTOR is used consistently for both scaling the background image and shifting its position, so the visible zoomed region always corresponds exactly to what the lens is currently covering. Changing ZOOM_FACTOR changes how much magnification is applied without breaking that alignment.

The lens position is clamped with Math.max/Math.min so it can never move past the image boundaries, keeping it fully within the visible photo at all times even when the cursor itself is right at the edge.

Yes — the zoom effect works by scaling up the same image file, so the maximum useful zoom level is limited by the source photo's native resolution. A low-resolution image will look blurry once magnified.

The demo uses a background-image because it makes the scale/position math for the zoom panel straightforward with plain CSS. Using an <img> tag would require the equivalent object-position and transform: scale math applied to the image element instead.

The base version relies on mouse hover events (mouseenter/mousemove/mouseleave), so it does not activate on touch. A touch-friendly version would need to listen for touchmove and possibly show the zoom panel in a modal or below the image instead of side by side.