Bento Layouts Tilt Me
I was recently playing around with Bento layouts (if you don’t know what Bento layout / grid is, it’s the new trend all the trendy designers are doing, catch up) and actually automating the layout process - basically using grid-auto-flow on grid layout. Then I got an idea: “Could I make the tiles dynamically tilt towards the mouse pointer?” Why? - Why not? Let’s do it.
Bento layouts actually don’t tilt me, sorry. I just wanted to use this awesome clickbait opportunity for what I’ve made. This semi-demo and tutorial will guide you on achieving this interactive effect.
Making a Single Tile Tilt
Tilting a single tile is straightforward, and a talented developer - Armando Canals, already did that.
All I needed to do was scale it by adding multiple tiles, inside a grid layout. The code is here, with the relevant parts described in the comments:
<style>
body {
background: #302c31;
}
.container {
height: 100%;
width: 100%;
/* Make it a grid */
display: grid;
/* 8 columns and 4 rows */
grid-template-columns: repeat(8, 100px);
grid-template-rows: repeat(4, 100px);
/* Make the layout dense = fill out any "holes" and leave uncompleted rows if necessary */
/* Try commenting the dense option out to see the difference */
grid-auto-flow: dense;
align-content: center;
justify-content: center;
gap: 8px;
}
.box {
background: white;
}
/* Here we make some if the tiles different size */
/* to see the effect of the grid layout */
.box:is(:nth-child(2), :nth-child(8), :nth-child(10)) {
grid-column: span 2;
grid-row: span 1;
}
.box:is(:nth-child(3), :nth-child(7), :nth-child(13)) {
grid-column: span 2;
grid-row: span 2;
}
</style>
<body>
<!-- Spawn multiple boxes -->
<div class="container" id="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</body>
<script>
// Try smaller numbers to see more tilt
let constrain = 30;
// the part where mouse movement will be taken into account
// replace with 'body' to consider the whole body of the webpage
let mouseOverContainer = document.getElementById("container");
// select all our boxes
let boxes = document.getElementsByClassName("box");
function transforms(x, y, el) {
let box = el.getBoundingClientRect();
let calcX = -(y - box.y - (box.height / 2)) / constrain;
let calcY = (x - box.x - (box.width / 2)) / constrain;
// try smaller perspective for more tilt. (may produce some fun artifacts)
return "perspective(500px) "
+ " rotateX("+ calcX +"deg) "
+ " rotateY("+ calcY +"deg) ";
}
function transformElement(el, xyEl) {
el.style.transform = transforms.apply(null, xyEl);
}
mouseOverContainer.onmousemove = function(e) {
let xy = [e.clientX, e.clientY];
window.requestAnimationFrame(function(){
// Calculate the transform for all our boxes
for (const box of boxes) {
let position = xy.concat([box]);
transformElement(box, position);
}
});
};
</script>
Bonus: Making the Highlight Pop
We can enhance the layout’s visual appeal - the tile can animate to pop out when hovered. To do that, we check whether we’ve hovered a smaller area inside the tile, and if so, we scale it. Simple and effective. To try it out, just replace your transforms function with the one below.
function transforms(x, y, el) {
let box = el.getBoundingClientRect();
let calcX = -(y - box.y - (box.height / 2)) / constrain;
let calcY = (x - box.x - (box.width / 2)) / constrain;
// try smaller perspective for more tilt. (may produce some fun artifacts)
let transformString = "perspective(500px) "
+ " rotateX("+ calcX +"deg) "
+ " rotateY("+ calcY +"deg) ";
// make the hover area half the tile's bounding box
const halfBox = {
left: box.left + box.width / 4,
right: box.right - box.width / 4,
top: box.top + box.height / 4,
bottom: box.bottom - box.height / 4,
}
// if the mouse is within the half-BBox,
// don't apply the rotation, but scale the tile instead
if (x >= halfBox.left && x <= halfBox.right
&& y >= halfBox.top && y <= halfBox.bottom) {
transformString = " scale(2) "
}
return transformString;
}
The End
Thank you for diving into this quick tutorial. Now that you are a cool kid, tweet (X?) me your creative Bento grid designs @devslovecoffee.
Explore my other posts and projects for more creative web design ideas ☕.