Image zoom on click as seen on the popular publishing platform.
You click on an image and it smoothly zooms in or out to fit the screen. You click again — it smoothly goes back to normal. You scroll — it also goes back.
- 🛠 Framework-agnostic — works with everything from Knockout.js to Web Components
- 👌 Zero-dependency
- 🧬 Perfect for dynamic content, mutation-agnostic — you can do whatever you want with images, it'll work
- ⚡️ Blazing fast — no matter if it's 10 images or 10000, it uses only two event listeners. Not per image, just two listeners. Complexity is always O(1)
- 🤓 Powered by quirky math to precisely calculate everything and do the trick with only one transformation
- 🦋 Looks good on both dark and light modes
- 🍦 Zero-configuration by default but extensible when you need it
- 🗿 Works flawlessly even on iOS Safari, in every orientation, with every image no matter the size and dimensions
npm install fast-image-zoom --save
or
yarn add fast-image-zoom
import imageZoom from 'fast-image-zoom'
imageZoom()
<script src="https://unpkg.com/fast-image-zoom@7.0.1/dist/fast-image-zoom.js"></script>
<script>
imageZoom()
</script>
That's it!
Plugin targets meaningful, content images:
<!-- yes -->
<img src="foo.jpg" alt="Cute kitten" />
<!-- no -->
<img src="bar.jpg" />
<img src="bar.jpg" alt="" />
Here are the defaults:
imageZoom({
selector: `img[alt]:not([alt=""]):not([data-image-zoom-disabled])`,
containerSelector: null,
cb: () => {},
exceed: false,
padding: 20,
})
-
selector
(string) is used to target images. By default it only targets meaningful images (e.g. ones withalt
), so your icons won't be magnified on click. -
containerSelector
limits plugin's scope to a certain element. It's useful for modals. Only the images inside that element will be clickable, and the scroll handler that un-zooms images will work on that element only. -
cb
(function) is called after the plugin is initialized. -
exceed
(boolean) defines whether images should exceed their natural size when zoomed. For example, if you zoom 100x100 image on a 1080p screen withexceed: false
, its final size will be 100px, meanwhile, withexceed: true
it will be 1080px. -
padding
(integer) defines a gap in pixels between a zoomed image and the closest edge of the viewport.
Note that if exceed
is false and smaller images appear to have a larger gap between their edges and the edge of the viewport, padding won't be added. For example, if you zoom a 100x100 image on a 1080p screen and your padding is set to 20, a natural gap between an image and the viewport edge would be (1080 - 100) / 2 = 490, thus there is no need to add that 20px gap.
Only pixels are supported by now.
You can explicitly define exceed
for a specific picture via a data attribute:
<img src="..." alt="..." data-image-zoom-exceed="true">
You can disable zooming for any image you like, even if it has alt
:
<img src="..." alt="..." data-image-zoom-disabled>
Note that if you redefine the selector
in a way that doesn't account data-image-zoom-disabled
attribute, this feature will stop working.
You can always hack the plugin redefining straightforward CSS:
.image-zoom,
.image-zoom-wrapper::after {
transition-timing-function: ease-in-out;
}
.image-zoom-wrapper::after {
background-color: hotpink;
}
For now, !important
might be needed, as styles are injected into <head>
. This will probably be changed in the future.
.image-zoom-wrapper
— element that wraps every image. Mimics itsdisplay
property. We use it to add page background and slightly separate the zoomed image from what's behind it..image-zoom-wrapper-zoomed
— the same wrapper but for when the image is zoomed..image-zoom
— the image itself that was processed and is interactive, ready to zoom..image-zoom-zoomed
— zoomed image.
Being called, the plugin returns the destroy function that you may call to remove event listeners. It will also remove related styles from <head>
and from the images themselves.
const destroy = imageZoom()
// don't need it anymore
destroy()
img
inline styles will be overwritten. Use CSS selectors to stylize images.img
shouldn't have transforms. If needed, wrap it with a container and apply transforms there instead.- Container's
overflow-x
will behidden
. IfcontainerSelector
is null, thenoverflow-x
will behidden
for the root element.
Enjoy!