Responsive Bento
CSS auto-fit/dense grid: multi-span cells elegantly reorganize when the container shrinks — zero JavaScript.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Cards has 41 effects, including 6 free. Explore the category →
3 usage examples



How it works
The core property is grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)) on .bento-responsive. The CSS engine calculates how many 80 px columns fit in the available width: when space for one column disappears, all columns widen at once and every cell recalculates its position — no JavaScript, no media queries.
grid-auto-flow: dense activates the dense packing algorithm: when a multi-span cell (2×2, 2×1, or 1×2) leaves a hole, the browser slides in the next smaller cell from the DOM. The layout stays compact at every width.
Three span classes declare each tile's footprint: .cell-large with grid-area: span 2 / span 2, .cell-wide with grid-column: span 2, and .cell-tall with grid-row: span 2. The transition: .5s cubic-bezier(.16, 1, .3, 1) makes the position jump visible when the column count changes.
The container has resize: horizontal and overflow: auto for the demo: the user drags the bottom-right handle and watches the reorganization live. In production, remove those two properties — the grid adapts to its parent's width on its own.
Accessibility
- No prefers-reduced-motion: the code contains no
@media (prefers-reduced-motion: reduce)block. The CSS transition always fires on reflow. Add one in production:@media (prefers-reduced-motion: reduce) { .bento-responsive .bento-cell { transition: none } }. - Text contrast:
var(--text-secondary)(#a1a1aa) onvar(--bg-card)(#12121a) → ratio ≈ 7.5:1, WCAG AA compliant (4.5:1 threshold for body text). - No interactive elements inside the grid — no focus-trap, no keyboard navigation issues for this static component.
- The
resize: horizontalhandle is mouse-only, not keyboard-accessible. In production, let the container follow its parent and test with DevTools or window resizing. - No
roleoraria-labelon the grid. For semantic content, addrole="list"on.bento-gridandrole="listitem"on each.bento-cell.
Browser compatibility
Requires CSS Grid with auto-fit and minmax — available in all modern browsers since 2017.
Without CSS Grid support, cells render in normal block flow — no JS errors, the page stays readable. The resize: horizontal handle is ignored by Safari and all mobile devices; the grid still adapts through its natural container width.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="bento-responsive-container">
<div class="bento-grid bento-responsive">
<div class="bento-cell cell-large">…</div>
<div class="bento-cell cell-wide">…</div>
<div class="bento-cell cell-tall">…</div>
<div class="bento-cell cell-small">…</div>
<div class="bento-cell cell-small">…</div>
<div class="bento-cell cell-wide">…</div>
<div class="bento-cell cell-small">…</div>
<div class="bento-cell cell-small">…</div>
</div>
<span class="resize-hint">Resize</span>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| minmax(80px, 1fr) | 80px | Minimum column width before auto-fit recalculates. Increase (e.g. 120px) for wider tiles and fewer columns; decrease for a denser mosaic effect. Edit inside the .bento-responsive rule. |
| grid-auto-rows: 60px | 60px | Height of each row unit. Increase for taller tiles — cell-large (2 rows) and cell-tall (2 rows) scale proportionally. |
| gap: 12px | 12px | Spacing between tiles. Reduce to 8px for a tighter look, increase to 20px for an airy premium layout. |
| transition: .5s cubic-bezier(.16, 1, .3, 1) | .5s | Duration and easing of the position change on reflow. Shorten to .2s for a snappy jump, or remove the line for an instant reposition. |
| --bg-card | #12121a | Background of neutral tiles (cell-small without a gradient). Replace with your brand color or a slightly elevated page background tint. |
| --border | rgba(255,255,255,0.08) | Tile border color. Increase opacity (0.15–0.2) for more definition, or switch to a solid color for a design accent. |
| grid-area: span 2 / span 2 | cell-large | Edit the spans in .cell-large, .cell-wide, and .cell-tall to create custom formats (e.g. span 3 / span 1 for a very tall 3-row tile). |
FAQ
resize: horizontal and overflow: auto on the container are a demo feature for dragging the handle and watching the live reflow. In production, remove both properties and let the container follow its parent's width: the auto-fit grid adapts on its own. To test, just resize the browser window or use DevTools responsive mode.auto-fit recalculates the column count all at once at each threshold: all cells reposition simultaneously. The dense algorithm then picks the best available slot, which may differ from the previous layout. To pin a key tile's position, give it a named grid-area (e.g. grid-area: hero) instead of a plain span..bento-cell is a standard flex container. Add background-image with background-size: cover for a photo, or insert any component (chart, card, video). The effect is 100% vanilla CSS: it works in React, Vue, Svelte, and Angular without modification.