JSFiddle - React, Tailwind, and code Playground
by Christian Sonne
HTML
<ul id="ballpit">
<li id="red"></li>
<li id="green"></li>
<li id="blue"></li>
<li id="orange"></li>
<li id="rebeccapurple"></li>
</ul>
SCSS
:root {
--animation-duration: 0.3s;
}
ul {
margin: 50px;
list-style: none;
}
li {
margin: 0;
padding: 0;
position: absolute;
width: 20px;
height: 20px;
transition: transform var(--animation-duration) ease-out;
}
li:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background-color: currentColor;
}
li.up:before {
animation: bounceup calc(var(--animation-duration) / 2) alternate 2 cubic-bezier(0.165, 0.84, 0.44, 1);
}
li.down:before {
animation: bouncedown calc(var(--animation-duration) / 2) alternate 2 cubic-bezier(0.165, 0.84, 0.44, 1);
}
@keyframes bounceup {
to {
transform: translateY(-20px);
}
}
@keyframes bouncedown {
to {
transform: translateY(20px);
}
}
#red {
color: red;
}
#green {
color: green;
}
#blue {
color: blue;
}
#orange {
color: orange;
}
#rebeccapurple {
color: rebeccapurple;
}
@for $i from 1 through 10 {
li:nth-child(#{$i}) {
transform: translateX(calc(25px * #{$i}))
}
}
JavaScript
ballpit.addEventListener("click", function(e) {
if (e.target.nodeName !== "LI") return;
let prev = document.querySelector("li.selected") || document.querySelector("li");
let next = e.target;
let tmp = prev.style.transform || window.getComputedStyle(prev).transform;
prev.style.transform = next.style.transform || window.getComputedStyle(next).transform;
next.style.transform = tmp;
prev.classList.add("down");
prev.classList.remove("up", "selected");
next.classList.add("selected", "up");
next.classList.remove("down");
})