Skip to main content

Opening or closing transition

To adjust opening or closing transition type use lightbox option showHideAnimationType (String). It supports three values - zoom (default), fade (default if there is no thumbnail) and none.

Animations are automatically disabled if user (prefers-reduced-motion: reduce).

zoom​

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--zoom-transition',
children: 'a',
showHideAnimationType: 'zoom',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.init();

If you're using a different datasource, for example Array of images and you still want to use zoom transition, please refer to Separate DOM and data guide.

fade​

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery:'#gallery--fade-transition',
children:'a',
showHideAnimationType: 'fade',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.init();

none​

Automatically selected if user agent (prefers-reduced-motion: reduce).

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--none-transition',
children: 'a',
showHideAnimationType: 'none',

// optionally disable zoom transition,
// to create more consistent experience
zoomAnimationDuration: false,

pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.init();

Transition duration and easing​

Use options showAnimationDuration and hideAnimationDuration (Integer, default 333).

Option easing (String, default cubic-bezier(.4,0,.22,1)) accepts any CSS timing-function. It is applied to any zoom transition (including double-tap).

Both options can be modified dynamically while PhotoSwipe is opened.

In the example below transition duration is set to 1000ms (1s). Easing is defined dynamically (opening transition gets ease-out-back, zoom transitions gets ease-in-out-back, and closing transition gets ease-in-back):

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';

const backEasing = {
in: 'cubic-bezier(0.6, -0.28, 0.7, 1)',
out: 'cubic-bezier(0.3, 0, 0.32, 1.275)',
inOut: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
};

const lightbox = new PhotoSwipeLightbox({
gallery:'#gallery--customized-transition',
children:'a',

showHideAnimationType: 'zoom',
showAnimationDuration: 1000,
hideAnimationDuration: 1000,

pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.on('firstUpdate', () => {
lightbox.pswp.options.easing = backEasing.out;
});
lightbox.on('initialZoomInEnd', () => {
lightbox.pswp.options.easing = backEasing.inOut;
});
lightbox.on('close', () => {
lightbox.pswp.options.easing = backEasing.in;
});
lightbox.init();

Animating from cropped thumbnail​

  1. Use thumbnail image that matches aspect ratio of the large image. Animation from thumbnails that are cropped on server side is not supported.
  2. Crop thumbnail via CSS using object-fit:cover. If you're using a different object-position - use Object Position plugin by Vova Yatsyuk, or adjust it manually via thumbBounds filter.
  3. Add data-cropped="true" attribute to links that open PhotoSwipe.
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery:'#gallery--cropped-thumbs',
children:'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.init();

Hiding elements that overlap thumbnails​

If you have some element that overlays thumbnail, you may want to fade it out when PhotoSwipe is opening, and fade it back in when PhotoSwipe is closed.

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery:'#gallery--badges',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});

let firstElWithBadge;
let lastElWithBadge;

// Gallery is starting to open
lightbox.on('afterInit', () => {
firstElWithBadge = lightbox.pswp.currSlide.data.element;
hideBadge(firstElWithBadge);
});

// Gallery is starting to close
lightbox.on('close', () => {
lastElWithBadge = lightbox.pswp.currSlide.data.element;
if(lastElWithBadge !== firstElWithBadge) {
showBadge(firstElWithBadge);
hideBadge(lastElWithBadge);
}
});

// Gallery is closed
lightbox.on('destroy', () => {
showBadge(lastElWithBadge);
});

lightbox.init();

function hideBadge(el) {
el.querySelector('.badge')
.classList
.add('badge--hidden');
};
function showBadge(el) {
el.querySelector('.badge')
.classList
.remove('badge--hidden');
}
.badge {
position: absolute;
bottom: 5px;
left: 5px;
padding: 5px;
color: #FFF;
background: rgba(0,0,0,0.5);
line-height: 1;
transition: opacity 100ms linear;
font-size: 16px;
font-weight: normal;
}
.badge--hidden {
opacity: 0;
}

You may use this technique to hide any element that might interfere with the transition. For example, fixed header, sharing icons or carousel arrows.