<div class="container">
<div class="grid">
<div class="item" data-id="1">1</div>
<div class="item" data-id="2">2</div>
<div class="item" data-id="3">3</div>
<div class="item" data-id="4">4</div>
<div class="item" data-id="5">5</div>
<div class="item" data-id="6">6</div>
<div class="item" data-id="7">7</div>
<div class="item" data-id="8">8</div>
<div class="item" data-id="9">9</div>
</div>
<div class="grid grid--shadow-map">
<div class="item" data-id="1"></div>
<div class="item" data-id="2"></div>
<div class="item" data-id="3"></div>
<div class="item" data-id="4"></div>
<div class="item" data-id="5"></div>
<div class="item" data-id="6"></div>
<div class="item" data-id="7"></div>
<div class="item" data-id="8"></div>
<div class="item" data-id="9"></div>
</div>
</div>
body {
margin: 0;
font-family: sans-serif;
min-height: 100vh;
}
.container {
position: relative;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(auto-fit, minmax(50px, 1fr));
min-height: 100vh;
}
.grid--shadow-map {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.item {
display: grid;
place-content: center;
font-size: 2rem;
color: #eea7;
background-color: #161616;
}
.grid--shadow-map .item {
background-color: transparent;
}
const lerp = (a, b, t) => (1 - t) * a + t * b;
const shadowColor = 'rgba(103, 58, 183, 0.5)';
let activeEl = null;
const groups = [
new Set([1, 3, 9]),
new Set([2, 5, 8]),
new Set([7, 4, 6]),
];
const grid = document.querySelector('.grid');
const gridShadow = document.querySelector('.grid--shadow-map');
const itemsShadow = Array.from(
gridShadow.querySelectorAll('.item'),
el => ({ el, currH: 0, prevH: 0 })
);
grid.addEventListener('mouseover', (e) => {
activeEl = e.target.closest('.item');
});
grid.addEventListener('mouseleave', (e) => {
activeEl = null;
});
function update() {
const activeId = activeEl?.dataset.id;
const activeGroup = activeId === null ? null : groups.find(g => g.has(+activeId));
itemsShadow.forEach(it => {
// const targetH = it.el.dataset.id === activeEl?.dataset.id ? 80 : 0;
const targetH = activeGroup && activeGroup.has(+it.el.dataset.id) ? 80 : 0;
it.currH = lerp(it.prevH, targetH, 0.05);
it.currH = Math.abs(it.currH - targetH) < 1 ? targetH : it.currH;
it.prevH = it.currH;
const blurRadius = it.currH;
const spreadRadius = it.currH / 4;
it.el.style.boxShadow = `0 0 ${blurRadius}px ${spreadRadius}px ${shadowColor}`;
});
requestAnimationFrame(update);
}
requestAnimationFrame(update);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.