How I Fixed Broken Portrait/Landscape Gallery Alignment (and Open-Sourced It)
Why I Built a Responsive Image Strip Gallery (and Published It for Every Framework) A few weeks ago I ran into a layout problem that sounds simple on paper: put portrait and landscape photos in the same row, aligned, w
Why I Built a Responsive Image Strip Gallery (and Published It for Every Framework)
A few weeks ago I ran into a layout problem that sounds simple on paper: put portrait and landscape photos in the same row, aligned, without cropping them into ugly square boxes.
It turned out that no gallery — not Squarespace's built-in options, not the popular npm galleries — actually solves this cleanly. So I built one myself: image-strip-gallery, a fixed-column strip gallery that works in React, Vue, Angular, Svelte, plain JS, and as a copy-paste block for Squarespace and WordPress.
Here's the problem, why the usual answers fall short, and how the package solves it.
The problem: masonry breaks on mixed orientations
Squarespace's Section and Masonry gallery types are great for uniform grids, but they have a specific weakness — they don't keep portrait and landscape images aligned on the same row. Because masonry layouts stack images into columns of varying height, a tall portrait photo and a wide landscape photo end up with mismatched row baselines. You lose that clean, editorial "strip" look where six photos of different shapes sit level with each other.
This isn't a hypothetical problem — I found a whole Squarespace forum thread of people asking for exactly this and getting workarounds instead of a real fix.
The usual workaround — and why it's a bad trade
The common fix is to force every image into the same crop box: uniform width, uniform height, object-fit: cover. Rows do line up — but you lose composition. A landscape shot gets cropped into a square, a portrait gets its subject clipped. For photography-led sites (portfolios, product shots, editorial layouts), that's not acceptable.
What the package actually does
Instead of cropping, the gallery keeps each image's natural aspect ratio and solves alignment at the row level:
- A fixed number of images per row (default: 6 desktop, 2 mobile)
- Every row shares one height
- Each image's width is calculated from its own aspect ratio to fit that shared row height
- Portrait and landscape images sit side by side in the same row, fully aligned, uncropped
The result is the "strip" look people were asking for on that forum thread — without the crop-box compromise.
Built for how people actually ship sites today
Because I do full-stack work across Laravel, Vue, and React projects — and because half my audience for this needed a no-code option — I shipped it two ways:
- A copy-paste HTML/CSS/JS version for Squarespace and WordPress — no npm, no build step, just paste into a Code Block and Custom CSS panel.
- An npm package with dedicated entry points for React/Next.js and Vue/Nuxt, plus a vanilla-JS core that works directly in Angular, Svelte, or plain HTML.
It's lightweight (no jQuery dependency), SSR-safe for Next.js, includes an optional row-by-row fade-in animation, and every layout parameter — columns, gap, breakpoint, row height, animation timing — is configurable.
npm install @meerathanki09/image-strip-gallery
import { ResponsiveImageStripGallery } from '@meerathanki09/image-strip-gallery/react';
<ResponsiveImageStripGallery
images={images}
columns={{ desktop: 6, mobile: 2 }}
onImageClick={(image, index) => console.log(index, image)}
/>
Why I'm sharing this
I build a lot of client sites where photography matters — portfolios, product pages, event galleries — and I kept hitting this same wall. Rather than solving it once per project, I built it as a reusable, framework-agnostic package and published it publicly so anyone hitting the same forum thread I found doesn't have to choose between misaligned rows and cropped photos.
If you're dealing with the same layout problem, the package is free and MIT-licensed:
👉 npmjs.com/package/@meerathanki09/image-strip-gallery
Feedback, issues, and PRs welcome.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.