HTML
<div class="bento-container cols-1-3-1 rows-1-3-1">
<div data-column="0" data-row="0" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-image-1.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="1" data-row="0" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-image-2.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="2" data-row="0" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-image-3.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="0" data-row="1" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-image-6.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="1" data-row="1" class="bento-item center-piece">
<img src="https://assets.codepen.io/16327/portrait-image-4.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="2" data-row="1" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-image-8.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="0" data-row="2" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-image-14.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="1" data-row="2" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-pattern-3.jpg" alt="">
<div class="image-overlay"></div>
</div>
<div data-column="2" data-row="2" class="bento-item">
<img src="https://assets.codepen.io/16327/portrait-pattern-1.jpg" alt="">
<div class="image-overlay"></div>
</div>
</div>
CSS
:root {
--bg-color: #f0f2f5;
--gap: 15px;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
/* The Bento Grid Logic */
.bento-container {
display: grid;
gap: var(--gap);
width: 90vw;
height: 90vh;
max-width: 1000px;
max-height: 800px;
}
/*
Specific classes for each event target
*/
.bento-container.rows-3-1-1 {
grid-template-rows: 3fr 1fr 1fr;
}
.bento-container.rows-1-3-1 {
grid-template-rows: 1fr 3fr 1fr;
}
.bento-container.rows-1-1-3 {
grid-template-rows: 1fr 1fr 3fr;
}
.bento-container.cols-3-1-1 {
grid-template-columns: 3fr 1fr 1fr;
}
.bento-container.cols-1-3-1 {
grid-template-columns: 1fr 3fr 1fr;
}
.bento-container.cols-1-1-3 {
grid-template-columns: 1fr 1fr 3fr;
}
.bento-item {
background-color: var(--card-color);
border-radius: 12px;
box-shadow: 0 4px 6px rgba(255, 252, 225, 0.25);
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: #333;
position: relative;
cursor: pointer;
overflow: hidden;
border: 1px solid rgba(255, 252, 225, 0.5);
img {
position: absolute;
inset: 0;
object-fit: cover;
width: 100%;
height: 100%;
z-index: 1;
}
.image-overlay {
position: absolute;
inset: 0;
background-color: #333;
opacity: 0;
z-index: 2;
}
}
/* Hover Effect: Scale up and bring to front */
.bento-item:hover {
z-index: 10;
}
JS
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://unpkg.com/gsap@3/dist/Flip.min.js"></script>
<script>
jQuery(document).ready(function($) {
console.clear();
gsap.registerPlugin(Flip);
const bentoContainer = document.querySelector(".bento-container");
const bentoItems = bentoContainer.querySelectorAll("[data-row]");
const rowClasses = ["rows-3-1-1", "rows-1-3-1", "rows-1-1-3"];
const colClasses = ["cols-3-1-1", "cols-1-3-1", "cols-1-1-3"];
// Remember 0 index for the classes array, same for the data attribute on the HTML elements
let activeColumn = 1,
activeRow = 1,
doFlip = false;
bentoItems.forEach((e, i) => {
const colNumber = e.dataset.column;
const rowNumber = e.dataset.row;
e.addEventListener("mouseenter", () => {
// console.log("Item", i, "column", colNumber, "row", rowNumber);
const state = Flip.getState(bentoItems);
if (colNumber !== activeColumn) {
bentoContainer.classList.remove(colClasses[activeColumn]);
bentoContainer.classList.add(colClasses[colNumber]);
activeColumn = colNumber;
doFlip = true;
}
if (rowNumber !== activeRow) {
bentoContainer.classList.remove(rowClasses[activeRow]);
bentoContainer.classList.add(rowClasses[rowNumber]);
activeRow = rowNumber;
doFlip = true;
}
doFlip &&
Flip.from(state, {
duration: 0.4,
ease: "power2.out",
onStart: () => (doFlip = false),
absolute: true
});
});
});
bentoContainer.addEventListener("mouseleave", () => {
// Toggle the boolean just in case
doFlip = true;
// Get the state
const state = Flip.getState(bentoItems);
// Update the classes in the container
bentoContainer.classList.remove(colClasses[activeColumn]);
bentoContainer.classList.remove(rowClasses[activeRow]);
bentoContainer.classList.add(colClasses[1]);
bentoContainer.classList.add(rowClasses[1]);
// Update the index values
activeColumn = 1;
activeRow = 1;
// Run the Flip Animation
Flip.from(state, {
duration: 0.4,
ease: "power2.out",
onStart: () => (doFlip = false),
absolute: true
});
});
});
</script>




