Transform pinch-to-zoom gestures into smooth, precise page-level zoom with continuous granularity
npm install smooth-pinch-zoom



Transform pinch-to-zoom gestures into smooth, precise page-level zoom with continuous granularity.
Unlike browser zoom that jumps between fixed levels (100%, 125%, 150%), this library provides surgical precision - zoom to exactly 137%, 63%, or any percentage you want!
Replaces the magnifying glass effect with clean, coherent page-level zoom that keeps your interface usable at any zoom level.
Try it now! - Experience surgical precision zoom in action!
Test all features: pinch gestures, wheel zoom, animations, and custom zoom levels. See how smooth and precise the zoom really is!
- ๐ฏ Continuous precision: Zoom to any percentage (137%, 63%, 142.5%)
- ๐ฑ Cross-platform: Works on desktop trackpads, mobile touch, and tablets
- ๐ฑ๏ธ Multiple input methods: Pinch gestures + Ctrl+scroll wheel
- ๐ก๏ธ Accessibility friendly: Preserves native browser zoom (Ctrl+/-)
- ๐ Minimal dependencies: Only depends on Pithos (my own maintained package)
- ๐๏ธ Highly configurable: Custom zoom ranges, callbacks, and behaviors
- ๐งน Memory safe: Proper cleanup and event listener management
This library is fully accessible and preserves all native browser accessibility features:
- โ
Screen readers: Works seamlessly with assistive technologies
- โ
Keyboard navigation: Ctrl+/- shortcuts remain functional
- โ
Zoom preferences: Respects user's browser zoom settings
- โ
WCAG compliant: Meets accessibility standards
``bash`
npm install smooth-pinch-zoom
- ES Modules (Recommended)
`javascript
import { enableSmoothPinchZoom } from "smooth-pinch-zoom";
// Enable with default settings
const zoom = enableSmoothPinchZoom();
// Listen to zoom changes
window.addEventListener("smoothZoomChange", (e) => {
console.log(Zoom: ${e.detail.percentage}%);`
});
- UMD (Browser)
`html`
Important: You must declare the CSS variable --zoom in your CSS:
`css`
:root {
--zoom: 1;
}
This variable will be automatically updated by the library to reflect the current zoom level.
`javascript
import { enableSmoothPinchZoom } from "smooth-pinch-zoom";
// Basic usage with defaults
const zoom = enableSmoothPinchZoom();
// Listen to zoom changes
window.addEventListener("smoothZoomChange", (e) => {
console.log(Zoom: ${e.detail.percentage}%);`
});
`javascript`
const zoom = enableSmoothPinchZoom({
minZoom: 0.5, // 50% minimum
maxZoom: 3.0, // 300% maximum
wheelIncrement: 0.01, // 1% per scroll
});
`javascriptZoomed to ${percentage}%
const zoom = enableSmoothPinchZoom({
onZoomChange: (zoomLevel, percentage) => {
console.log();`
updateZoomIndicator(percentage);
},
});
`javascript`
const zoom = enableSmoothPinchZoom({
shouldAllowZoom: (source, target) => {
// Block zoom on map elements
if (target && target.closest(".map-container")) {
return false;
}
return true;
},
});
Now that you have the basics, you can:
1. Customize zoom ranges - Adjust minZoom and maxZoomonZoomChange
2. Add callbacks - Use to update your UI
3. Explore advanced options - See the full configuration below
4. Check the demo - Try the interactive examples
The library follows this priority order for configuration:
1. Library Configuration (highest priority) - Options passed to SmoothPinchZoom()user-scalable=no
2. Viewport Meta Tag - to disable browser zoom
3. Default Values (lowest priority) - Built-in fallbacks
The library provides SCSS utility functions for automatic zoom management:
- z-clamp() - Create responsive clamp() values that adapt to zoomz-fixed()
- - Keep elements at fixed size regardless of zoomz-100vh()
- and z-100vw() - Fullscreen dimensions that adapt to zoom
Quick example:
`scss
@use "smooth-pinch-zoom/scss" as *;
.my-element {
padding: z-clamp(0.5rem, 1rem, 2rem);
width: z-fixed(200px);
height: z-100vh(-60px);
}
`
For detailed documentation, examples, and advanced usage, see the SCSS README.
| Option | Type | Default | Description |
| --------------------------- | -------- | ------- | --------------------------------------- |
| minZoom | number | 0.25 | Minimum zoom level (25%) |maxZoom
| | number | 5.0 | Maximum zoom level (500%) |wheelIncrement
| | number | 0.01 | Zoom step for wheel scroll (1%) |enablePinchZoom
| | boolean | true | Enable touch/trackpad pinch |enableWheelZoom
| | boolean | true | Enable Ctrl+wheel zoom |enableZoomControl
| | boolean | true | Enable zoom control UI component |enableLocalStorage
| | boolean | true | Enable zoom persistence in localStorage |useExperimentalCssZoom
| โ ๏ธ | boolean | false | Enable CSS zoom (experimental) |onZoomChange
| | function | - | Callback for zoom changes |shouldAllowZoom
| | function | - | Guard to control when zoom is allowed |customZoomApplicator
| | function | - | Custom zoom implementation |
`javascript
// Programmatic control
zoom.setZoom(137); // Set to exactly 137%
zoom.getZoom(); // Get current zoom percentage
zoom.resetZoom(); // Reset to 100%
zoom.zoomIn(15); // Zoom in by 15%
zoom.zoomOut(10); // Zoom out by 10%
// Lifecycle
zoom.destroy(); // Clean up and reset
// Static methods
SmoothPinchZoom.isSupported(); // Check browser support
`
Listen to the global smoothZoomChange event:
`javascript${source} zoom: ${percentage}%
window.addEventListener("smoothZoomChange", (event) => {
const { zoomLevel, percentage, source } = event.detail;
console.log();`
});
Perfect for map applications where users need precise zoom control:
`javascript`
const mapZoom = enableSmoothPinchZoom({
minZoom: 0.1, // Zoom out to see whole world
maxZoom: 10, // Zoom in to street level
customZoomApplicator: (zoom) => {
mapContainer.style.zoom = zoom;
updateMapTiles(zoom);
},
});
For applications requiring precise image inspection:
`javascript`
const imageZoom = new SmoothPinchZoom({
maxZoom: 8, // 800% for detailed inspection
wheelIncrement: 0.02, // 2% per scroll for fine control
onZoomChange: (level, percent) => {
updateZoomIndicator(percent);
},
});
Provide smooth zoom while preserving browser accessibility:
`javascript${percent}%
// This replaces pinch-zoom behavior but keeps Ctrl+/- working
enableSmoothPinchZoom({
onZoomChange: (level, percent) => {
// Update your app's zoom indicator
document.querySelector(".zoom-level").textContent = ;`
},
});
`javascript`
// Essential methods you'll use most
zoom.setZoom(137); // Set to exactly 137%
zoom.getZoom(); // Get current zoom percentage
zoom.resetZoom(); // Reset to 100%
zoom.destroy(); // Clean up and reset
- โ
Chrome 61+
- โ
Firefox 91+
- โ
Safari 13+
- โ
Edge 79+
- โ
Mobile browsers with VisualViewport API
Feature Detection:
`javascript`
if (SmoothPinchZoom.isSupported()) {
enableSmoothPinchZoom();
} else {
console.warn("Smooth pinch zoom not supported");
}
Browser zoom limitations:
- Fixed steps: 25%, 33%, 50%, 67%, 75%, 90%, 100%, 110%, 125%, 150%, etc.
- Can't zoom to 137% or 63% precisely
Pinch-to-zoom problems:
- Acts like a magnifying glass
- UI elements fall off screen
- Interface becomes unusable
This library's solution:
- โ
Continuous precision: Any percentage you want
- โ
Clean page-level zoom: Interface stays coherent
- โ
Best of both worlds: Smooth gestures + proper zoom behavior
- โ
Performance optimized: Uses transform: scale() by default
- โ
No rendering delays: Smooth 60fps zoom experience
The library offers two zoom implementation strategies:
Default (Recommended): useExperimentalCssZoom: false
- Uses transform: scale() everywhere
- Optimal performance and smooth rendering
- No rendering delays or visual glitches
- Works consistently across all browsers
Experimental: useExperimentalCssZoom: true
- Uses CSS zoom property on supported browsers
- May cause rendering delays and performance issues
- Known bug: Elements can take time to render after zoom
- Only enable if you specifically need CSS zoom behavior
`javascript
// Performance optimized (default)
const zoom = new SmoothPinchZoom({
useExperimentalCssZoom: false, // Uses transform: scale()
});
// Experimental mode (may have performance issues)
const zoom = new SmoothPinchZoom({
useExperimentalCssZoom: true, // Uses CSS zoom where supported
});
`
- Hardware acceleration: transform is GPU-accelerated
- No layout recalculation: Only visual transformation
- Smooth animations: 60fps rendering guaranteed
- Cross-browser consistency: Same behavior everywhere
Pinch gestures not working?
- Check that VisualViewport API is supported
Zoom too sensitive?
- Reduce wheelIncrement (try 0.005 for finer control)minZoom
- Adjust /maxZoom range
Layout issues?
- Use customZoomApplicator to target specific elements
- Test with different CSS zoom vs transform approaches
Rendering delays or slow zoom?
- This is a known issue with CSS zoom property on some browsersuseExperimentalCssZoom: false
- Solution: Keep (default)transform: scale()
- The library automatically uses for optimal performance
Try the live demo to see smooth-pinch-zoom in action:
`bash``
cd example
npm install
npm start
The demo showcases all features with interactive examples and responsive design.
Contributions welcome! Please check the GitHub repository.
MIT License - feel free to use in your projects!