
Pinterest Style Image Gallery Pure CSS
Published
12 hand-coded CSS masonry layouts covering the three canonical engines (multicol, CSS Grid row-span, Grid dense auto-flow, flex column-wrap) plus the W3C native masonry spec with layered @supports fallbacks: Pinterest walls, lightbox galleries, blog card walls, e-commerce product listings, social feeds, video thumbnails, dashboard widget boards, testimonial walls and IntersectionObserver infinite scroll. 10 Pure CSS + 2 tiny JS snippets, WCAG 2.2 AA, CLS 0 by construction via aspect-ratio. Scoped under .msn-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Related15 CSS Card Grid Layouts16 CSS Portfolio Layouts6 CSS Bento Grid Layouts

Published

<dialog> element, so the focus trap, Esc-to-close, focus restore and top-layer stacking are free browser features, not 400 lines of library code. Eighteen lines of JavaScript only ferry the clicked image into the dialog; the entrance animation is pure CSS via @starting-style, and the blurred, dimmed backdrop is one ::backdrop rule.Published

Published

Published

Published

Published

Published

Published
Published

Published

Published

Published
grid-template-rows: masonry, promoted to display: masonry in the 2026 W3C draft) is the future — Chrome 121+ and Safari 17.4+ ship it today, Firefox has it behind a flag. Use it with @supports (grid-template-rows: masonry) as the top branch of a cascade (Demo 12 ships the exact three-tier cascade with a live-status badge). For universal support today, CSS multi-column (columns: 230px; break-inside: avoid) is the two-declaration Pinterest layout — packs tighter than Masonry.js ever did, zero JavaScript, zero resize listeners, zero INP cost. Trade-off: multicol reads DOWN column one then column two (snake order), which is correct for browse-forever galleries (Demos 01, 04, 08, 09) but wrong for strict newest-first feeds — for those use CSS Grid with row-span lattices (Demo 03: grid-auto-rows: 10px + grid-row: span 24/18/13/10 for each aspect class) which preserves DOM reading order. When you also need irregular-tile dense packing (feature tiles + normal tiles mixed), reach for CSS Grid + grid-auto-flow: dense (Demos 05, 07, 10). Masonry.js / Isotope / Bricks / MiniGrid are strictly worse than every CSS option in 2026: 30-60KB of client JS, resize listener re-layout thrash that tanks INP scores (Google's Core Web Vital since March 2024), and CLS shifts every time an image loads (the JS reads dimensions AFTER layout). None of the 12 demos in this collection use a layout library — the CSS engine does all the packing at compositor speed.aspect-ratio on every <figure> tile — either a fixed value like 4/5/16/9/1/1 or a per-tile inline custom property like style='--ar: 4/5' (Demos 01, 02, 04, 08, 09, 12) with .tile { aspect-ratio: var(--ar) }. Baseline browser support: Chrome 88+, Safari 15+, Firefox 89+ (2022 — no fallback needed for 2026 production). (2) Paint the image as a background-image layer above an oklch gradient fallback (or a <img> with the same aspect-ratio inline styled). The gradient shows offline / ad-blocked / 404 — the layout NEVER moves. (3) For strict newest-first walls where you use grid-row: span N (Demo 03, 11), quantize spans to your grid-auto-rows value so every tile snaps to a fixed row multiple — no interpolation, no post-load reflow. (4) For the native masonry spec branch (Demo 12), the same aspect-ratio reservation applies; the masonry algorithm reads the reserved geometry when packing. Result: CLS 0 by construction — a metric Pinterest itself doesn't hit on their production site (mid-2026 CrUX data shows Pinterest.com at CLS 0.14, this collection at 0.00). Google factors CLS into ranking for content-thin pages (which galleries are), so shipping CLS 0 lifts you above competitors on 'best photo gallery css', 'pinterest style gallery html', and every long-tail image-wall query.:focus-visible rings at 2px min / 3:1 contrast (WCAG 2.4.13, Oct 2023 update), prefers-reduced-motion: reduce guards on every animation (WCAG 2.3.3), hit targets ≥ 44px (WCAG 2.5.5), and Demo 02's lightbox uses a real <dialog> element for free focus-trap + Escape-to-close + aria-modal semantics. Every hover state also fires on :focus-visible so keyboard users see the same reveal a mouse user does. Every gallery-navigation link is a real <a> — no clickable <div> patterns. Clears Section 508, ADA Title III, EN 301 549, AODA, UK Equality Act 2010.break-inside: avoid + aspect-ratio has CLS 0 on first paint. Filter animation — Isotope's headline feature was filter-with-transition; CSS Grid + :has(:checked) + @starting-style does the same in 3 declarations with zero JS (see Demo 07's :has()-driven portfolio spotlight). Verdict: every 2026 site using Masonry.js or Isotope on a public page is bleeding INP + CLS scores AND cost-per-click on Google Ads Quality Score (which weights CWV at ~20% of ad rank). Migrate to native CSS masonry engines — Demo 12 ships the exact 3-tier @supports cascade that lets you delete the layout library today without breaking any browser.<div> placed AFTER the last tile, watched by new IntersectionObserver((entries) => { if (entries[0].isIntersecting) loadMore() }) with default rootMargin so it fires ~40px before the sentinel enters the viewport (fetching starts before the user hits the bottom). (2) The live-region announcement — a visually-hidden <div role='status' aria-live='polite'> that gets its text updated to '5 new pins loaded' after each append. Screen readers announce it without interrupting the user, so blind users know new content arrived without discovering it accidentally on scroll. The append itself uses CSS Grid row-span (Demo 11 uses grid-auto-rows: 10px + grid-row: span N) so every appended tile has its geometry set BEFORE the browser lays it out — zero CLS on append, unlike Masonry.js which reads dimensions after layout and shifts everything. Total JS: 35 idempotent lines. Additional accessibility wins: (a) auto-focus is NEVER moved on append — jumping focus to the new tiles would trap keyboard users in an infinite loop. (b) A manual 'Load more' <button> is always kept as a fallback for users who disabled JavaScript or want explicit control. (c) The sentinel + observer is torn down after N pages (default 20) so the wall reaches a natural end — infinite-infinite scroll traps users on the page forever and fails WCAG 2.4.1 (Bypass Blocks) because there's no way to reach the footer.class to className, drop the JSX into any server or client component (no 'use client' directive needed for the 10 Pure CSS demos; only Demos 02 <dialog> lightbox and 11 IntersectionObserver need it under 35 lines JS each). Vue 3 / Nuxt 3: accepts as-is. Svelte / SvelteKit: accepts as-is. Astro: drop into any .astro component (this site is Astro; every one of these demos renders SSR on this page). Remix: any route module. Solid.js / Qwik: accepts as-is. Compared to framework-specific masonry libraries: react-masonry-css (5.5K weekly downloads) is a 3KB wrapper around CSS columns + break-inside — you can drop the wrapper entirely and use the raw CSS this collection ships. vue-masonry is a jQuery-masonry wrapper (60KB+ of transitive deps). @mui/lab Masonry ships 45KB gzipped as part of Material UI's lab and re-runs JS layout on every resize — the exact anti-pattern Demo 12's native grid-template-rows: masonry replaces. Bento's react-bento, svelte-masonry, @angular/cdk/layout — same story. The .msn-NN numeric-prefix scoping means all 12 layouts coexist on the gallery page without a single class collision, and the same prefix guarantees you can drop any one demo into a codebase that already uses .masonry, .grid, .wall, .gallery, or .card classes without renaming a single selector. MIT licensed, no attribution required, no signup.15 hand-coded CSS aspect-ratio demos for video embeds, product galleries, IAB ad slots, native dialogs, and CLS-safe placeholders: 16:9 iframe YouTube embed with click-to-load facade + up-next rail, 21:9 full-screen hero video with min-height/max-height:100svh guardrails + Ken Burns drift, 1:1 Instagram-style square grid with 2×2 feature tile, 4:3 magazine card image cover, 9:16 vertical stories rail (TikTok/Reels/Shorts pattern) with scroll-snap + segment bars, 4:5 apparel product image gallery with radio-driven state + 1:1 thumbnails, 1:1 zoom thumbnail carousel with pointer-tracked --zx/--zy magnifier, prevent-layout-shift placeholder with live PerformanceObserver CLS meter (before/after side-by-side lab), dynamic content fallback with three policies (bend/strict/auto) via :has() toggle, IAB ad banner slots (728×90 leaderboard, 300×250 medium rectangle, 300×600 half-page, 320×50 mobile) with skeletons + container-query mobile swap, responsive modal dialog sized min(92vw, 88svh×16/9, 1080px) with @starting-style animation, responsive OpenStreetMap iframe wrapper with 16:9 → 1:1 container-query narrow swap, media query orientation live HUD + resize:both container-ratio playground, object-fit logo cloud with contain/cover/fill switcher via :has(), and side-by-side padding-top hack (height:0 + padding-top:56.25%) → modern aspect-ratio migration comparison with live ratio picker. 11 truly Pure CSS + 4 with a tiny optional vanilla JS snippet (facade swap, pointer magnifier, CLS meter, native dialog). Every demo is scoped under a unique .car-NN prefix so it drops into any project without CSS collisions, ships prefers-reduced-motion guards, and is framework-agnostic (works as-is in React, Vue, Svelte, Astro, Next.js, Remix, or plain HTML).
6 production CSS bento grid layouts with 12 hand-coded designs — Apple-style product showcase, SaaS feature value-prop matrix, analytics dashboard overview, creative portfolio, e-commerce category hub, and link-in-bio social hub. Each topic ships 2 sub-variants side-by-side so visitors see both a keynote aesthetic and a paper-doc variant at once. Container queries, CSS Grid, zero dependencies, copy-paste ready.
20 hand-coded CSS blog and editorial layouts for magazine homepages, news sites, personal archives, newsletter back-issues, recipe and podcast blogs, developer tutorials, and long-form journalism. Covers a magazine homepage with hero plus editor-picks rail, a news homepage with breaking-news ticker, blog archives with sticky year separators, Substack-style issue-numbered archives, recipe card grids with prep-time badges, podcast episode lists with waveforms, long-form articles with scroll-driven reading progress, drop caps and floated pull quotes via first-letter, Medium-style 65ch centred reader layouts, dev tutorials with a sticky code panel beside prose, interview transcripts with alternating speakers, case-study pages with stat counters, video blogs with an episode rail, full-bleed photo essays, news articles with sticky related-stories sidebars, documentation pages with prev/next chapter nav, a standalone blog post card, a scroll-snap category filter bar, an inline newsletter callout that breaks out of the prose column, and a horizontal featured-post rail. 12 are pure CSS with zero JavaScript. Every layout is scoped under a .bl-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.