← All posts

Tutorials

Image hover zoom — a lightbox without a library

Galleries, shops, stock-photo sites — thumbnails everywhere. To see an image in full, you have to click, wait, go back. This rule adds a hover preview: you hover a thumbnail, a larger version pops up by the cursor. A lightweight lightbox with no library at all.

The rule

The rule's JavaScript — URL pattern for the gallery you use, or * globally:

const box = document.createElement('img');
box.style.cssText =
  'position:fixed;pointer-events:none;z-index:99999;max-width:40vw;' +
  'max-height:80vh;box-shadow:0 8px 32px rgba(0,0,0,.4);' +
  'border-radius:8px;display:none';
document.body.appendChild(box);
addEventListener('mouseover', (e) => {
  const img = e.target.closest('img');
  if (!img) return;
  box.src = img.currentSrc || img.src;
  box.style.display = 'block';
});
addEventListener('mousemove', (e) => {
  box.style.left = (e.clientX + 24) + 'px';
  box.style.top = (e.clientY + 24) + 'px';
});
addEventListener('mouseout', () => { box.style.display = 'none'; });

How it works

One preview element

We create exactly one <img> and reuse it, only swapping its src. No DOM cleanup, no leaks.

pointer-events: none

The preview sits on top of the page. Without pointer-events: none it would catch mouse events itself — the cursor would "enter" the preview, mouseout would misfire and the preview would flicker. With this rule the preview is transparent to the mouse.

currentSrc versus src

img.currentSrc is the version the browser actually picked from srcset — usually sharper than src. We reach for it first, with src as a fallback.

position: fixed plus client coordinates

position: fixed places the preview relative to the window, and e.clientX/clientY is the cursor position relative to the window — they match, so the preview tracks the cursor regardless of scroll.

A variant — full size instead of the thumbnail

In many galleries the thumbnail has a URL like .../thumb/photo.jpg while the full size is .../large/photo.jpg. Swap box.src for the rewritten address:

box.src = (img.currentSrc || img.src).replace('/thumb/', '/large/');

The pattern differs site to site — look at the src of a thumbnail and of a full photo, find the difference.

Pitfalls

See also

Install JustZix — and view photos without clicking each one.

Rate this post

No ratings yet — be the first.

Try it yourself

Install JustZix and paste any snippet from this article. Two minutes from zero to a working rule across all your devices.

Get JustZix

Features · How it works · Examples · Use cases