Basic Bento
4×3 CSS Grid with six asymmetric cells: scale 1.05 and violet glow on hover, spring transition — pure CSS, zero JavaScript.
This effect is free — the Cards category contains 41 effects total, including 6 free. Effect.Labs has 811 vanilla effects. Explore the category →
Usage examples
How it works
The layout is a repeat(4, 1fr) / repeat(3, 1fr) grid with six deliberately asymmetric cells: .cell-1 spans 2 columns × 2 rows via grid-area: span 2 / span 2, .cell-4 through .cell-6 each span two columns (grid-column: span 2), and .cell-2 / .cell-3 each occupy one column. The featured cell naturally draws the eye without ever breaking the Grid flow.
On hover, each cell simultaneously receives a transform: scale(1.05), a z-index: 10 to rise above its neighbors without triggering a layout reflow, a border tint of rgba(99, 102, 241, 0.5), and a box-shadow with 40 px violet diffusion. The spring transition cubic-bezier(0.175, 0.885, 0.32, 1.275) over 0.4 s produces a slight overshoot that makes the cell feel like it leaps toward the viewer.
A pseudo-element ::before at position: absolute; inset: 0 carries a linear-gradient(135deg, rgba(99,102,241,0.1) 0%, transparent 50%). Its opacity transitions from 0 to 1 on hover with a separate 0.3 s transition — the cell's top-left corner gently illuminates, adding depth without impacting render performance.
The effect is pure CSS: the file also includes seven ready-to-use variants — .bento-images, .bento-animated, .bento-interactive, .bento-stats, .bento-reveal, .bento-cardstack, and .bento-responsive. Cells rely on four design-system CSS variables: --bg-card, --radius-lg, --border, and --text-secondary — define or override them inline based on your context.
Accessibility
- No prefers-reduced-motion in the provided CSS: scale and glow transitions always run regardless of the OS preference. For compliant projects, add
@media (prefers-reduced-motion: reduce) { .bento-cell { transition: none; } }. - The
div.bento-cellelements are plaindivs with notabindex,role, oraria-label: not keyboard-focusable, and the:hovereffect is not triggered by Tab or Enter. - The container and grid have no ARIA roles in the base HTML — add them to match your semantic use (e.g.
role="region"+aria-label). - Text contrast depends on the
--text-secondaryand--bg-cardCSS variables defined by your theme — verify the WCAG AA ratio (≥ 4.5:1) in your own context. - To make cells keyboard-accessible (links, buttons), add
tabindex="0"on each cell and duplicate the:hoverrules under:focus-visible.
Browser compatibility
Relies on CSS Grid (grid-template-columns, grid-area: span) and CSS Custom Properties — natively supported since Chrome 57 / Firefox 52 / Safari 10.1. Zero JavaScript dependency.
On IE11 and browsers without CSS Grid, cells fall back to display: block and stack vertically — no JS errors, the page stays readable.
The code
Copy the three blocks into your page. No dependencies.
<div class="bento-container">
<div class="bento-grid bento-basic">
<div class="bento-cell cell-1">Featured</div>
<div class="bento-cell cell-2">A</div>
<div class="bento-cell cell-3">B</div>
<div class="bento-cell cell-4">Wide</div>
<div class="bento-cell cell-5">C</div>
<div class="bento-cell cell-6">D</div>
</div>
</div>
.bento-container {
width: 100%;
max-width: 600px;
aspect-ratio: 4 / 3;
}
.bento-grid {
display: grid;
gap: 12px;
width: 100%;
height: 100%;
}
.bento-cell {
background: var(--bg-card);
border-radius: var(--radius-lg);
border: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.85rem;
color: var(--text-secondary);
position: relative;
overflow: hidden;
}
.bento-basic {
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 1fr);
}
.bento-basic .cell-1 {
grid-area: span 2 / span 2;
}
.bento-basic .cell-2 {
grid-column: span 1;
}
.bento-basic .cell-3 {
grid-column: span 1;
}
.bento-basic .cell-4 {
grid-column: span 2;
}
.bento-basic .cell-5 {
grid-column: span 2;
}
.bento-basic .cell-6 {
grid-column: span 2;
}
.bento-basic .bento-cell {
transition: 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.bento-basic .bento-cell:hover {
transform: scale(1.05);
z-index: 10;
border-color: rgba(99, 102, 241, 0.5);
box-shadow: rgba(99, 102, 241, 0.3) 0px 20px 40px;
}
.bento-basic .bento-cell::before {
content: "";
position: absolute;
inset: 0px;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, transparent 50%);
opacity: 0;
transition: opacity 0.3s;
}
.bento-basic .bento-cell:hover::before {
opacity: 1;
}
.bento-images .cell-1 {
grid-area: span 2 / span 2;
}
.bento-images .cell-2 {
grid-column: span 2;
}
.bento-images .cell-3 {
grid-area: span 2 / span 1;
}
.bento-images .cell-4 {
grid-column: span 1;
}
.bento-images .cell-5 {
grid-column: span 2;
}
.bento-images .cell-6 {
grid-column: span 1;
}
.bento-images .bento-cell {
background-size: cover;
background-position: center center;
cursor: pointer;
}
.bento-images .cell-1 {
background: linear-gradient(135deg, rgb(102, 126, 234) 0%, rgb(118, 75, 162) 100%);
}
.bento-images .cell-2 {
background: linear-gradient(135deg, rgb(240, 147, 251) 0%, rgb(245, 87, 108) 100%);
}
.bento-images .cell-3 {
background: linear-gradient(135deg, rgb(79, 172, 254) 0%, rgb(0, 242, 254) 100%);
}
.bento-images .cell-4 {
background: linear-gradient(135deg, rgb(67, 233, 123) 0%, rgb(56, 249, 215) 100%);
}
.bento-images .cell-5 {
background: linear-gradient(135deg, rgb(250, 112, 154) 0%, rgb(254, 225, 64) 100%);
}
.bento-images .cell-6 {
background: linear-gradient(135deg, rgb(161, 140, 209) 0%, rgb(251, 194, 235) 100%);
}
.bento-images .bento-cell .overlay {
position: absolute;
inset: 0px;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: 0.4s;
}
.bento-images .bento-cell .overlay span {
color: white;
font-weight: 700;
font-size: 1rem;
transform: translateY(20px);
transition: transform 0.4s;
}
.bento-images .bento-cell:hover .overlay {
opacity: 1;
}
.bento-images .bento-cell:hover .overlay span {
transform: translateY(0px);
}
.bento-animated .cell-1 {
grid-area: span 1 / span 2;
}
.bento-animated .cell-2 {
grid-area: span 2 / span 1;
}
.bento-animated .cell-3 {
grid-area: span 2 / span 1;
}
.bento-animated .cell-4 {
grid-column: span 2;
}
.bento-animated .cell-5 {
grid-area: span 1 / span 2;
}
.bento-animated .cell-6 {
grid-area: span 1 / span 2;
}
.bento-animated .bento-cell {
opacity: 0;
transform: translateY(30px) scale(0.9);
animation: 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal forwards running bentoFadeIn;
}
.bento-animated .cell-1 {
animation-delay: 0.1s;
background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%);
}
.bento-animated .cell-2 {
animation-delay: 0.2s;
background: linear-gradient(135deg, rgb(236, 72, 153) 0%, rgb(244, 63, 94) 100%);
}
.bento-animated .cell-3 {
animation-delay: 0.3s;
background: linear-gradient(135deg, rgb(6, 182, 212) 0%, rgb(59, 130, 246) 100%);
}
.bento-animated .cell-4 {
animation-delay: 0.4s;
background: linear-gradient(135deg, rgb(16, 185, 129) 0%, rgb(5, 150, 105) 100%);
}
.bento-animated .cell-5 {
animation-delay: 0.5s;
background: linear-gradient(135deg, rgb(245, 158, 11) 0%, rgb(239, 68, 68) 100%);
}
.bento-animated .cell-6 {
animation-delay: 0.6s;
background: linear-gradient(135deg, rgb(139, 92, 246) 0%, rgb(217, 70, 239) 100%);
}
.bento-animated .bento-cell span {
color: white;
font-weight: 700;
}
.bento-interactive .bento-cell {
cursor: pointer;
transition: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
background: var(--bg-elevated);
}
.bento-interactive .bento-cell.expanded {
z-index: 100;
background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%);
box-shadow: rgba(99, 102, 241, 0.4) 0px 25px 50px;
grid-area: span 2 / span 2 !important;
}
.bento-interactive .bento-cell .expand-icon {
width: 30px;
height: 30px;
border-radius: 50%;
background: rgba(99, 102, 241, 0.2);
display: flex;
align-items: center;
justify-content: center;
transition: 0.3s;
}
.bento-interactive .bento-cell:hover .expand-icon {
background: rgba(99, 102, 241, 0.4);
transform: scale(1.1);
}
.bento-interactive .bento-cell.expanded .expand-icon {
background: rgba(255, 255, 255, 0.2);
}
.bento-interactive .bento-cell.expanded .cell-content span {
color: white;
}
.bento-stats .cell-1 {
grid-area: span 2 / span 2;
}
.bento-stats .cell-2 {
grid-column: span 2;
}
.bento-stats .cell-3 {
grid-column: span 1;
}
.bento-stats .cell-4 {
grid-column: span 1;
}
.bento-stats .cell-5 {
grid-column: span 2;
}
.bento-stats .cell-6 {
grid-column: span 2;
}
.bento-stats .bento-cell {
flex-direction: column;
gap: 8px;
padding: 16px;
}
.bento-stats .cell-1 .stat-number {
font-size: 3rem;
}
.bento-stats .bento-cell:hover .stat-bar-fill {
width: var(--fill-width, 75%);
}
.bento-reveal .cell-1 {
grid-area: span 2 / span 2;
}
.bento-reveal .cell-2 {
grid-area: span 1 / span 2;
}
.bento-reveal .cell-3 {
grid-column: span 2;
}
.bento-reveal .cell-4 {
grid-area: span 1 / span 2;
}
.bento-reveal .cell-5 {
grid-column: span 2;
}
.bento-reveal .bento-cell {
cursor: pointer;
background: var(--bg-elevated);
}
.bento-reveal .bento-cell:hover .reveal-front {
opacity: 0;
transform: scale(1.2);
}
.bento-reveal .bento-cell:hover .reveal-back {
opacity: 1;
transform: scale(1);
}
.bento-reveal .bento-cell:hover {
border-color: rgba(99, 102, 241, 0.3);
box-shadow: rgba(99, 102, 241, 0.2) 0px 10px 30px;
}
.bento-cardstack .cell-1 {
grid-area: span 2 / span 2;
}
.bento-cardstack .cell-2 {
grid-area: span 2 / span 2;
}
.bento-cardstack .cell-3 {
grid-column: span 2;
}
.bento-cardstack .cell-4 {
grid-column: span 2;
}
.bento-cardstack .bento-cell {
padding: 16px;
background: var(--bg-elevated);
}
.bento-cardstack .bento-cell:hover .stacked-card:nth-child(1) {
transform: translate(-50%, -50%) translateX(-30%) rotate(-10deg);
}
.bento-cardstack .bento-cell:hover .stacked-card:nth-child(2) {
transform: translate(-50%, -50%) translateY(-5px);
}
.bento-cardstack .bento-cell:hover .stacked-card:nth-child(3) {
transform: translate(-50%, -50%) translateX(30%) rotate(10deg);
}
.bento-cardstack .bento-cell:hover .mini-card:nth-child(1) {
transform: translateY(-10px) rotate(-5deg);
}
.bento-cardstack .bento-cell:hover .mini-card:nth-child(2) {
transform: translateY(-15px);
}
.bento-cardstack .bento-cell:hover .mini-card:nth-child(3) {
transform: translateY(-10px) rotate(5deg);
}
.bento-responsive .bento-cell {
transition: 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.bento-responsive .bento-cell span {
color: white;
font-weight: 600;
font-size: 0.7rem;
}
.bento-responsive .bento-cell:hover {
transform: scale(1.05);
z-index: 10;
box-shadow: rgba(0, 0, 0, 0.3) 0px 15px 30px;
}
@keyframes bentoFadeIn {
100% {
opacity: 1;
transform: translateY(0px) scale(1);
}
}
/* Variables du design system du site, dont ce code depend. Sans elles,
l'acheteur obtenait des coins carres et des couleurs par defaut (revue Owen).
Valeurs reprises de css/style.css — a adapter librement. */
.bento-container {
--bg-card: #12121a;
--bg-elevated: #1a1a24;
--border: rgba(255, 255, 255, 0.08);
--radius-lg: 0.75rem;
--text-secondary: #a1a1aa;
}
// Effet CSS pur — pas de JavaScript nécessaire
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| --bg-card | theme-defined | Cell background — set to #1e1e2e for a uniform dark background. |
| --border | theme-defined | Border color (1px solid) — rgba(255,255,255,0.08) for a subtle line on dark backgrounds. |
| --radius-lg | theme-defined | Cell border-radius — 12px standard, 20px heavily rounded. |
| --text-secondary | theme-defined | Text label color — #94a3b8 for soft grey on dark backgrounds. |
| gap: 12px in .bento-grid | 12px | Space between cells — 8px for compact, 20px for airy. |
| rgba(99,102,241,…) in .bento-basic .bento-cell:hover and ::before | #6366f1 | Glow and overlay color — 3 occurrences to replace with your brand color. |
| transform: scale(1.05) in .bento-basic .bento-cell:hover | 1.05 | Hover zoom amount — 1.03 for subtle, 1.08 for pronounced. |
| transition: 0.4s cubic-bezier(0.175,0.885,0.32,1.275) in .bento-basic .bento-cell | 0.4s spring | Duration and curve — 0.25s ease-out for a linear feel without overshoot. |
FAQ
Does Basic Bento work without JavaScript?
Yes, it is 100% CSS — not a single line of JavaScript. Copy the HTML and CSS and the effect works immediately in any framework (React, Vue, Svelte) or in plain HTML.
How do I change the violet glow color?
The color #6366f1 appears in three places in the CSS: border-color on hover, box-shadow on hover, and the ::before gradient. Replace all occurrences of rgba(99,102,241,…) with your brand color for a consistent theme.
Can I use the other grid variants included in the CSS?
Yes. The CSS includes seven ready-to-use variants: .bento-images (cells with images and text overlay), .bento-animated (entry fadeIn animation), .bento-interactive (expand on click), .bento-stats (metrics), .bento-reveal, .bento-cardstack, and .bento-responsive. Just swap the .bento-basic class on the grid div — the six-cell HTML structure stays the same.