Leave your email to get notified. Powered by MailChimp, unsubscribe any time.
All basic gestures are supported: flick to the next or previous image, spread to zoom in, drag to pan, pinch to zoom out or close, tap to toggle the controls, double-tap to zoom.*
*You can assign your own actions for tap and double-tap gestures.
PhotoSwipe manipulates the browser’s history so that the user can link to each gallery item and close the gallery via the “back” button. The initial URL is restored when the gallery is closed.
This feature comes as a module. You can exclude it from the build entirely, or fork it to fit the requirements of your product’s URL structure.
PhotoSwipe creates the illusion of faster loading.
Photos are displayed before they fully load. This feature is disabled on touch devices because it could cause swipe transitions to lag.
Pass the source of a thumbnail to PhotoSwipe, which will display it instantly and load the full-sized image over top.
Just a stretched thumbnail or gray placeholder is used, with the full image progressively loaded over top.
Luke Wroblewski on spinners:
“It’s like watching the clock tick down—when you do, time seems to go slower.”
If at least a tiny part of the image has not loaded for 1 second or a browser does not support progressive loading, a spinning progress indicator smoothly fades in. A delay is added to avoid blinking in case the image was cached or the user has a fast connection.
The zoom transition to open the gallery wasn’t added merely for a fancy effect. The image starts loading before the animation, so users on fast connections might not even notice that something was loading.
PhotoSwipe loads neighboring images based on the direction of the user’s movement. You can control how many images to preload through the API.
Because images in a gallery are loaded dynamically, you can pass the source that is appropriate to the user’s window size and DPI.
More about responsive images →
PhotoSwipe emulates the default behavior of the browser’s image viewer.
If an image is smaller than the viewport, PhotoSwipe will show a zoom cursor over the image and zoom icon in the top bar.
When an image is zoomed in, the user can pan across it via the mouse wheel or the trackpad or by dragging it. And if you need to extend this functionality, you can use the API, of course.
The UI is entirely separated from the core of the script. If you’re making a custom interface for a gallery, you would write it instead of the default interface, not on top of it. Default PhotoSwipe UI is responsive – optimized for desktop, tablets and mobile devices.
To draw the most attention to the photos, controls are hidden when the mouse hasn’t moved for 2 seconds or when the mouse moves off the window.
PhotoSwipe can be closed simply by scrolling the page (on non-touch devices), thus avoiding any extra movement of the mouse.
The background can be set to any color and transparency level.
The vertical margins between images can be controlled through an API.
PhotoSwipe is treated as a modal dialog, so
aria attributes are added, and the gallery gains focus when it is open.
Images are displayed at their highest possible size and are not limited by the width of the column or wrapper. Each image is isolated from the other content and fits the viewport vertically, so that the user can focus on it. If an image is larger than the viewport, it can be zoomed (which most galleries are unable to do).
Let’s say the viewport on a user’s phone is 500 pixels wide and your uncompressed image is 1200 pixels wide. You wouldn’t want to serve such a large image on mobile, so perhaps you’d resize it to 500 pixels. But if the image has important details and the user zooms it, it will look pixelated. With PhotoSwipe, when the user taps the small image (500 pixels), the large one will load (1200 pixels), thus preserving all of the detail.
Compared to a list of images, one after another
PhotoSwipe saves users’ bandwidth because it doesn’t load all images at once — just nearby images according to the user’s direction of movement. Also, it occupies less space on the page, and you can directly link to individual images in a gallery.
PhotoSwipe might not be a good idea if…
- … your images are small or low quality or if there would be no point in zooming or isolating them. Use a simple list of images or a horizontal scroller instead.
- … your images are very large and should never be scaled (for example tall infographics with text). Simply link to image file, or create separate HTML page just with image.
- … your captions are long or more important than the images themselves. Consider using a simple list of images, with captions below or beside them. And when the user clicks on an image for which a larger version is available, then you could open PhotoSwipe, without the caption, to draw attention to the image itself.
- … your website’s layout is not fluid. On a non-responsive website on a small screen, PhotoSwipe’s controls would look tiny because the page will be zoomed out. Consider using Magnific Popup instead.
PhotoSwipe is built for performance and integration with your product needs.
PhotoSwipe is broken down into modules. All of them, except the controller, events & gestures and framework bridge, may be excluded from your build to reduce the size. You’re free to edit any of these to fit your requirements. Built with Grunt, linted with JSHint.
basic functionality, like switching items or zooming
- User interface
all buttons and their actions, captions, etc. (the interface is built exclusively with public methods — an example of what the API can do)
- Events & gestures
touch, pointer, mouse events and gestures
managing gallery items; adding content to the gallery; returning the sizes of images
- Framework bridge
generic functions, like
addEventListener; feature detection
changes URL’s hash suffix (
#); enables browser’s “back” button to close gallery
- Desktop zoom
clicking to zoom; panning with trackpad or mouse wheel.
firing tap and double-tap events
The total size of core modules (Gzip’d) is about 11 KB + 3 KB UI, which is about three times lighter than jQuery 1.11 and only 2 KB heavier than FancyBox.
The CSS comes out to 0.5 KB core + 1.5 KB skin + single SVG or PNG icons sprite. Uses Sass preprocessor.
RequestAnimationFrameis used wherever possible.
- Only the
opacityproperties are animated. Almost no paints occur during animation, making transitions as smooth as possible.
- The frames-per-second (FPS) rate largely depends on the sizes of the images and the device itself. For example, landscape-oriented images that are 1000 pixels wide and displayed in portrait mode on an iPhone 4s running iOS 8 will animate smoothly at 60 FPS. If the images were 1400 pixels wide, then the FPS rate would drop noticeably.
- PhotoSwipe keeps only three images in the DOM at once, because each “slide” is a composited layer, which consumes quite a lot of memory.
- Almost no memory is consumed until the gallery is first opened.
- The script has been tested for memory leaks. Navigating images back and forth and creating or deleting a gallery doesn’t leave a trace in memory.
The script has been developed to work on every device, which means that basic functionality should be supported everywhere:
- desktop Chrome, Firefox, Safari, Opera and IE 8 and above
- Android 2.3.7+ (2.1 not tested yet): default browser, Chrome, Firefox (latest), Dolphin (latest)
- iOS 5+
- Windows Phone 7+: default browser (touch gestures are supported from 8+)
- BlackBerry OS 10+: default browser (older versions not tested yet)
- devices with multiple input methods (Surface, Chromebook Pixel, etc.)
If you discover a problem on your device, please open an issue on GitHub, and provide as much detail as possible (OS name and version, browser name and version, screenshot or screencast, etc.).
If both touch and mouse input methods are detected, the script waits for two consecutive
mousemove events to occur and only then applies the mouse-only features (for example left/right arrow buttons).
How the zoom animation works for opening images
- Once a thumbnail is clicked, its large version instantly starts loading.
- Meanwhile, PhotoSwipe creates a fixed-positioned layer with the duplicated thumbnail image, background, buttons and caption. The background and controls are styled with
opacity: 0.001(if it had
opacity: 0, the paint would not occur in some browsers).
- A 50-millisecond timer starts. It is added to give the browser time to render the new layers (background, controls, image). Otherwise, the animation would start with a noticeable lag. TODO: change this delay depending on browser/os/device?
- Three CSS transitions start: one scales the image (
translateare animated), the second changes the opacity of the background, and the third changes the opacity of the controls.By default, the transition lasts 333 milliseconds.
The background is a separate element, because animating
opacitylooks much smoother than animating an RGBa
- Once the transition is complete, the large image is added on top of the stretched thumbnail, whether or not it’s fully loaded.
- To make the swipe transition smooth, the two neighboring slides are readied at the sides of the viewport.
- If lazy-loading is enabled on more than two neighboring images, then those images would start to load now, too.
PhotoSwipe does not force any HTML markup into the gallery — you have full control. Images will be crawlable if you'll have list of links to large images or the images themselves.
The script is free to use for personal and commercial projects. It falls under the MIT license with one exception: Do not create a public WordPress plugin based on it, as I will develop it.
If you need to use it for a public WordPress plugin right now, please ask me by email first. Thanks!
Attribution is not required, but much appreciated, especially if you're making product for developers.
The script was created by Code Computerlove, a digital agency in Manchester. In March 2014, it passed on development to Dmitry Semenov.
The new version of PhotoSwipe (4.0) was entirely rewritten, supports a much longer list of devices, and contains a lot of performance and UX improvements. Built-in support for jQuery Mobile has been dropped.
Letter is sent only when I release a new product, article or important update. Not more often than 3 times a year. Powered by MailChimp, unsubscribe any time.