Design Masonry Layout (Pinterest-style)
Reported
2 times
Last seen
2024-09-05
First seen
2024-09-05
Active in
2024, 2025
Description
Design a masonry layout component like Pinterest or Unsplash that renders a grid of variable-height cards without gaps. **Requirements:** - Cards have unknown heights (images, text, mixed content) - Layout adapts to container width (responsive columns) - Smooth loading experience (no layout shifts) - Must handle 10,000+ items efficiently - Support infinite scroll / pagination **Visual Example:** ``` | Card A | Card B | Card C | | (tall) | (short) | (med) | | | Card D | | | | (med) | Card F | | Card E | | (short) | | (short) | Card G | | ``` Cards are packed tightly — each new card goes into the shortest column, like filling water into cups.
Approach Tips
**Layout Algorithm:** Greedy column assignment — always place the next item in the shortest column: ```javascript function layout(items, numColumns, columnWidth, gap) { const columnHeights = new Array(numColumns).fill(0); return items.map(item => { const col = columnHeights.indexOf(Math.min(...columnHeights)); const x = col * (columnWidth + gap); const y = columnHeights[col]; columnHeights[col] += item.height + gap; return { ...item, x, y, col }; }); } ``` **Implementation Approaches (discuss tradeoffs):** | Approach | Pros | Cons | |----------|------|------| | Absolute positioning | Full control, works everywhere | Manual calculation, no reflow | | CSS `columns` | Simple, pure CSS | Poor ordering (fills column-first not row-first) | | CSS Grid + `grid-row: span N` | Native, clean | Requires known heights upfront | | **Recommended: Absolute pos** | Best for dynamic content | Needs resize observer | **Performance for 10K+ items — Virtualization:** - Only render items in the viewport + buffer (200px above/below) - Use `IntersectionObserver` to detect items entering/leaving viewport - Keep a "layout map" of all positions in memory but only mount visible DOM nodes - Recycle DOM nodes as user scrolls (object pooling) **Responsive Design:** - Calculate column count from container width: `Math.floor(width / (minColWidth + gap))` - Use `ResizeObserver` on the container to re-layout on resize - Debounce re-layout (16ms = one frame) **Image Loading (prevent layout shift):** - Require aspect ratio in the data (`width/height` from API) - Calculate display height before image loads: `displayHeight = columnWidth / aspectRatio` - Use placeholder (blurred thumbnail / solid color) until image loads - `loading="lazy"` + IntersectionObserver for below-the-fold images **What interviewers look for:** - Do you understand the core algorithm (shortest-column greedy)? - Can you discuss CSS approaches and explain *why* you chose absolute positioning? - Performance awareness: virtualization, lazy loading, resize handling - Edge cases: images failing to load, extremely tall items, dynamic content changes **Follow-ups:** - How would you animate items when the layout changes (e.g., on filter)? - How would you handle drag-and-drop reordering? - What changes for a server-rendered masonry layout (SSR)?
Sources
Rippling
HR Tech/SaaS
Typically appears in: Onsite - System Design
60 min — Design a large-scale system. Focus on multi-tenancy, data modeling, and distributed architecture.