Gallery✨ Premium

Pan Zoom

Your image stays enlarged one and a half times inside its frame; the mouse, a finger or the arrow keys pick the visible part, and it recentres when you leave.

JSTransform-origin

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Gallery has 44 effects, including 6 free. Explore the category →

3 usage examples

Panoramic canvas in an online gallery — exploring the landscape with the mouse — Pan Zoom example 1

① Panoramic canvas in an online gallery — exploring the landscape with the mouse

WhenOn the Brenadine Gallery website, the canvas “Morning on the lake” fills the screen behind the navigation bar and a card giving its size, year and price. The visitor moves the mouse across the peaks, the lake and the house by the water.
WhyA large canvas squeezed to the width of a screen loses its texture; enlarged and steered by the mouse, it can be explored as if standing at the gallery wall, without opening a viewer.
SettingsRoot in position: absolute; inset: 0, --pnz-width: 100%, --pnz-ratio: 540/360, --pnz-radius: 0, --pnz-scale: 1.4; bar and card laid on top with pointer-events: none so the hover goes through.
Poster proof before printing — checking the corners — Pan Zoom example 2

② Poster proof before printing — checking the corners

WhenIn the Quiravelle Printing customer area, the “Brass Night” poster proof sits on the left; on the right, the list of checked items and the “Approve proof” and “Request changes” buttons. The customer hovers the poster to see the crop marks and the licence line at the bottom.
WhyOn a proof, mistakes hide in the margins and the fine print: an image that is always enlarged makes you look closely, and the mouse leads the eye to the corners.
Settings--pnz-width: 170px, --pnz-ratio: 5/7 (the poster's format), --pnz-radius: 2px, default enlargement (1.5); drop shadow added by the scene.
Mini park map in a theme park's info bar — Pan Zoom example 3

③ Mini park map in a theme park's info bar

WhenOn the Ferlimousse Park home page, a white block gathers a small map, waiting times and the “Tickets” button. Hovering the map scrolls through the four lands and shows the wait at each ride.
WhyThe whole map would be unreadable at 166 px; enlarged, it shows one area at a time and the mouse chooses which: a preview that orients you before opening the full map.
Settings--pnz-width: 166px, --pnz-ratio: 3/2, --pnz-radius: 10px, --pnz-scale: 1.7.

How it works

The <img class="pnz-image"> is permanently enlarged by transform: scale(var(--pnz-scale)) (1.5) and the .pnz-frame clips the overflow. Only part of the image shows at a time, the centre at rest.

The script only changes the origin of that enlargement (transform-origin). Under the mouse or finger it works out the position as a percentage of the frame and uses it as the origin: the hovered corner of the image comes to the matching edge of the frame, which feels like moving the photo around. A --pnz-follow transition (0.1 s) smooths the tracking. When you leave the frame, the origin returns to 50% 50%.

Each .fx-0182-root on the page gets its own wiring, with no fixed id: two frames never drive each other and pasting the script twice has no side effect. The frame follows the available width up to --pnz-width.

Accessibility

  • Keyboard: the frame takes Tab focus; arrow keys shift the visible area by 5% of the image (20% with Shift), Escape or leaving the frame recentres it.
  • Touch: dragging a finger over the image explores it; the frame holds back page scrolling during the gesture (touch-action: none). Lifting the finger recentres the image.
  • Screen readers: the frame is a named group and the image keeps its alt text; the enlargement removes nothing from what is read.
  • Reduced motion: under prefers-reduced-motion: reduce, the visible area jumps straight to the target point, without sliding.

Browser compatibility

CSS transforms, Pointer Events, aspect-ratio and 2 KB of JavaScript, no dependency. Measured in Chromium 151, Firefox 153 and WebKit 26.5: two independent copies, script pasted twice without error, arrow keys, a real finger at 390 px in Chromium, no overflow.

Chrome 88+✓ Full (measured)
Firefox 89+✓ Full (measured)
Safari 15+✓ Full (WebKit engine measured)
Edge 88+✓ Full (Chromium engine)
Mobile iOS 15+✓ Full (WebKit engine measured)
Android Chrome 88+✓ Full (Chromium engine)

Without JavaScript, the image stays enlarged and centred, with no exploring. Without aspect-ratio (before Chrome 88 and Safari 15), the frame takes the image's natural height.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0182-root">
  <div class="pnz-frame" tabindex="0" role="group" aria-label="Enlarged image: hover it, drag a finger or use the arrow keys to explore it">
    <img class="pnz-image" src="your-photo.jpg" alt="Photo description">
    <span class="pnz-label" aria-hidden="true">Pan Around</span>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Image (HTML — src of .pnz-image) violet grid pattern (inline SVG) Your photo and its alt. Use a file at least --pnz-scale times wider than the frame to keep it sharp.
--pnz-scale 1.5 Permanent enlargement. 1.2 for a gentle move, 2 or more to read a detail.
--pnz-follow 0.1s How long the view takes to reach the target point; 0s for crisp tracking, 0.3s for a slower glide.
--pnz-width · --pnz-ratio · --pnz-radius 280px · 7 / 5 · 0.75rem Maximum width, proportions and rounding of the frame; 100% for a full-width image.
.pnz-label caption “Pan Around” Text centred on the image; delete it on a real photo.
touch-action (.pnz-frame rule) none Switch to pan-y if the image is very tall on mobile: the page will scroll vertically and finger exploring happens by sliding sideways.

FAQ

No: that is the point, the image stays enlarged and the frame shows part of it. For a zoom that only kicks in on hover or on click, see Hover Zoom or Click to Zoom.
When the pointer leaves the frame, the finger lifts, Escape is pressed or focus is lost, the origin is reset to 50% 50%. Remove the pointerleave listener from the script to keep the last position.
Yes: set --pnz-width: 100% and your image's proportions in --pnz-ratio. The maths use percentages of the frame, so its real size does not matter.