Bento with Images
Asymmetric 4×3 CSS grid with six gradient-background cells and a sliding text overlay activated on hover.
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 layout uses a 4×3 CSS Grid (4 columns, 3 rows) in which six cells span different areas via grid-area: span N / span M — the main cell covers 2×2, others stretch across 1 or 2 columns. No manual width calculations are needed: the browser distributes space automatically via repeat(4, 1fr).
Each cell carries a unique 135° linear gradient defined directly in the .cell-1 to .cell-6 selectors (violet-indigo, pink-red, blue-cyan, green-teal, pink-yellow, lavender-pink). background-size: cover is already set on .bento-images .bento-cell, so gradients can be swapped for real images without touching the structure.
The overlay is a <div class="overlay"> with position: absolute; inset: 0, background rgba(0,0,0,0.4), and opacity: 0 at rest. The selector .bento-images .bento-cell:hover .overlay raises opacity to 1 in a 0.4 s CSS transition. The entire hover effect is 100% CSS — no JavaScript event listener handles it.
The <span> inside the overlay starts at transform: translateY(20px) and slides to translateY(0) on hover via transition: transform 0.4s — the label rises from the bottom of the cell at the same time the overlay darkens.
Accessibility
- prefers-reduced-motion absent: the code contains no
@media (prefers-reduced-motion: reduce)— opacity and translateY transitions (0.4 s) run even when the OS requests reduced motion. Add@media (prefers-reduced-motion: reduce) { .bento-images .bento-cell .overlay, .bento-images .bento-cell .overlay span { transition: none !important; } }to comply with WCAG 2.3.3. - Overlay text contrast: white on
rgba(0,0,0,0.4)over a gradient → ratio ≥ 4.5:1 in all cases — WCAG AA compliant. - Keyboard navigation: cells have
cursor: pointerbut notabindexor keyboard handler — the overlay cannot be triggered via Tab/Enter. Addtabindex="0"and a:focus-within .overlayrule if cells must be keyboard-reachable. - No ARIA attributes on the grid or cells (no
roleoraria-label). If cells serve as links or buttons, wrap them in<a>or<button>elements and provide accessible labels. - Overlay text labels (Design, Photo…) are in the normal DOM flow and readable by screen readers without extra ARIA — they are only visually hidden via
opacity: 0.
Browser compatibility
Requires CSS Grid Level 1 and the :hover pseudo-class — universally supported since 2017.
Without CSS Grid (IE 10 unsupported), cells stack vertically as full-width blocks — content stays readable. On touch screens, :hover does not fire; the overlay stays hidden. Add a touchstart handler or a :focus-within rule to toggle the overlay on tap.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="bento-container">
<div class="bento-grid bento-images">
<div class="bento-cell cell-1"><div class="overlay"><span>Design</span></div></div>
<div class="bento-cell cell-2"><div class="overlay"><span>Photo</span></div></div>
<div class="bento-cell cell-3"><div class="overlay"><span>Video</span></div></div>
<div class="bento-cell cell-4"><div class="overlay"><span>3D</span></div></div>
<div class="bento-cell cell-5"><div class="overlay"><span>Motion</span></div></div>
<div class="bento-cell cell-6"><div class="overlay"><span>Art</span></div></div>
</div>
</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 |
|---|---|---|
| --radius-lg | 0.75rem | Corner radius for all cells. 0 = sharp corners, 1.5rem = very rounded tiles. |
| --border | rgba(255,255,255,0.08) | Border color for each cell. Increase the alpha or change the color to mark cell separation more clearly. |
| gap (.bento-grid selector) | 12px | Gap between cells. 8 px = tight magazine look, 20 px = airy layout. |
| Gradients .cell-1 to .cell-6 | 6 distinct 135° gradients | Each selector carries an independent background: linear-gradient(…). Replace with background-image: url(…) for real photos — background-size: cover is already in place. |
| overlay background (.overlay selector) | rgba(0,0,0,0.4) | Opacity and color of the hover veil. Increase alpha for better readability on light backgrounds; decrease it to let more of the background show through. |
| transition duration (.overlay selector) | 0.4s | Duration of the overlay fade. 0.2 s = snappy, 0.7 s = smooth. |
| translateY initial (.overlay span selector) | translateY(20px) | Initial text offset before hover. Increase to 40 px for a more dramatic slide, or switch to translateX for a lateral direction. |
FAQ
background-size: cover is already set on .bento-images .bento-cell. Simply replace background: linear-gradient(…) with background-image: url(your-image.jpg) in each .cell-N selector — no other change needed.:hover → opacity + transform). The JS bundled with the effect manages other Bento variants (animated, interactive, stats) and does not touch any .bento-images cell.grid-template-columns and grid-template-rows in the .bento-images selector, then adjust the grid-area: span N / span M values in .cell-1 to .cell-6. For 5 cells, remove .cell-6 and redistribute the spans to fill the grid without an empty slot.