#2185·PhotoSwipe

Placeholder is sized by width only, so a thumbnail with a different aspect ratio is drawn at the wrong height

Author: reagleCreated Aug 14, 2026Updated Aug 14, 2026

PhotoSwipe version: 5.4.4 Browser: Chrome (also reproducible in incognito, so not an extension)

Summary

Placeholder.setDisplayedSize() scales the image placeholder by width and lets its height follow the thumbnail's own aspect ratio. When the thumbnail's aspect ratio differs from the full image's — common in gallery generators that crop thumbnails to a fixed size — the placeholder is drawn taller or shorter than the image it stands in for.

The user-visible result is a distracting flicker on open: for a fraction of a second a blurred band of the photo extends past where the image actually ends, and then snaps to the correct size once the full image paints. It reads as a rendering glitch rather than as a progressive-loading effect, and it is most noticeable on the very interaction that should feel smoothest — clicking a thumbnail to open the lightbox.

Cause

In src/js/slide/placeholder.js:

javascript
setDisplayedSize(width, height) {
  if (this.element.tagName === 'IMG') {
    // Use transform scale() to modify img placeholder size
    // (instead of changing width/height directly).
    // This helps with performance, specifically in iOS15 Safari.
    setWidthHeight(this.element, 250, 'auto');
    this.element.style.transformOrigin = '0 0';
    this.element.style.transform = toTransformString(0, 0, width / 250);
  } else {
    setWidthHeight(this.element, width, height);
  }
}

For the IMG branch the rendered height is 250 / thumbnailAspectRatio, scaled by width / 250 — so the final height is width / thumbnailAspectRatio. The height argument is ignored. The div branch just below uses both dimensions and is correct.

Steps to reproduce

  1. Build a gallery whose thumbnails are cropped to a fixed size — e.g. 280x210 (4:3) — while the photos have other aspect ratios.
  2. Give the anchor correct data-pswp-width / data-pswp-height for the full image (e.g. 1152x768, 3:2) and set msrc to the cropped thumbnail.
  3. Open that slide.

Expected: the placeholder occupies exactly the box the full image will.

Actual: the placeholder is width / (4/3) tall instead of width / (3/2), i.e. ~12% too tall. It overhangs the bottom of the image and then jumps to the right size when the full image paints — a brief but distracting flicker on every open. With the dynamic caption plugin (type: 'below') the overhang lands on top of the caption text, which makes it look especially broken. It affects the first slide opened, the only one that gets an image placeholder (content.js: this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false).

Suggested fix

Honour the height argument in the IMG branch — either by scaling the two axes independently, or by setting explicit width/height on the element and letting object-fit: cover crop the thumbnail into the correct box. The latter keeps a single transform for the iOS 15 performance reason noted in the comment, while making a mismatched thumbnail fill the right rectangle rather than dictating its shape.

Workaround

Suppress the image placeholder so PhotoSwipe uses the correctly sized div:

javascript
lightbox.addFilter('placeholderSrc', () => false);

This costs the blurred preview, but nothing is ever drawn at the wrong shape.