<div class="grid"></div>
:root {
--cols: 0;
--rows: 0;
}
* {
box-sizing: border-box;
position: relative;
}
body {
background: #000;
overflow-x: hidden;
}
.grid {
pointer-events: none;
}
.row {
display: flex;
}
.cell {
flex: 1;
padding-bottom: calc(100% / var(--cols));
perspective: 1000px;
}
.item {
position: absolute;
top: 1px;
left: 1px;
right: 1px;
bottom: 1px;
z-index: 1;
}
.grid .item {
will-change: transform;
}
View Compiled
var frag = document.createDocumentFragment();
var grid = document.querySelector(".grid");
var rows = 100;
var cols = 7;
var observer = new IntersectionObserver(handleIntersect, {
rootMargin: (1 / cols * 100) + "% 0px"
});
TweenLite.set("html", {
"--cols": cols,
"--rows": rows
});
for (var r = 0; r < rows; r++) {
var hue = r / rows * 360;
var row = createElement("row", frag);
var tl = row._timeline = new TimelineLite({ paused: true })
for (var c = 0; c < cols; c++) {
var cell = createElement("cell", row);
var item = createElement("item", cell);
TweenLite.set(item, {
autoAlpha: 0,
force3D: true,
backgroundColor: "hsl(" + hue + ",80%," + random(50, 70) + "%)",
scale: Math.random() < 0.8 ? 0 : random(1.1, 1.3),
rotationX: random(-180, 180),
rotationY: random(-180, 180),
rotationZ: random(-180, 180),
xPercent: random(-300, 300),
yPercent: random(-300, 300)
});
tl.to(item, random(0.4, 1), {
autoAlpha: 1,
scale: 1,
rotationX: 0,
rotationY: 0,
rotationZ: 0,
xPercent: 0,
yPercent: 0
}, random(0.15));
}
tl.progress(1);
}
grid.appendChild(frag);
for (var i = 0; i < grid.children.length; i++) {
observer.observe(grid.children[i]);
}
function handleIntersect(entries, observer) {
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
if (entry.isIntersecting) {
entry.target._timeline.play();
} else {
entry.target._timeline.pause(0);
}
}
}
function createElement(className, parent) {
var element = document.createElement("div");
element.className = className;
parent.appendChild(element);
return element;
}
function random(min, max) {
if (max == null) { max = min; min = 0; }
if (min > max) { var tmp = min; min = max; max = tmp; }
return min + (max - min) * Math.random();
}
This Pen doesn't use any external CSS resources.