<h1>
Here is some text
<span class="wrapper">
<span class="item" data-animated-item>
<svg height="20" width="20">
<circle cx="10" cy="10" r="5" />
</svg>
</span>
<span class="item" data-animated-item>
<svg height="16" width="16">
<circle cx="8" cy="8" r="4" />
</svg>
</span>
<span class="item" data-animated-item>
<svg height="16" width="16">
<circle cx="8" cy="8" r="4" />
</svg>
</span>
<span class="item" data-animated-item>
<svg height="24" width="24">
<circle cx="12" cy="12" r="6" />
</svg>
</span>
<span class="animated-text">where this is magic</span>
</span>
and this isn't
</h1>
@import url("https://fonts.googleapis.com/css2?family=DM+Serif+Display&display=swap");
.wrapper {
display: inline-block;
position: relative;
}
h1 {
font-size: clamp(2.5rem, 2vw, 4.25rem);
}
.item {
display: block;
position: absolute;
opacity: 0;
width: clamp(20px, 1.5vw, 30px);
aspect-ratio: 1;
}
.animated-text {
background: linear-gradient(
to right,
var(--purple),
var(--violet),
var(--pink),
var(--purple)
);
background-size: 200%;
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
background-clip: text;
white-space: nowrap;
}
circle {
fill: var(--violet);
}
:root {
--bg: #1c1c2e;
--purple: rgb(123, 31, 162);
--violet: rgb(103, 58, 183);
--pink: rgb(244, 143, 177);
}
html {
box-sizing: border-box;
block-size: 100%;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
body {
min-block-size: 100dvh;
font-family: "DM Serif Display", serif;
padding: 1rem;
display: grid;
place-items: center;
background: var(--bg);
color: white;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
const wrapper = document.querySelector(".wrapper");
const items = gsap.utils.toArray(".item");
let isHovering = false;
function animateItem(item) {
if (isHovering) {
gsap.fromTo(item, {
opacity: 1,
x: () => gsap.utils.random(0, wrapper.offsetWidth - item.offsetWidth),
y: "random(-80, 120)"
}, {
y: "-=20",
opacity: 0,
duration: 1.5,
delay: gsap.utils.random(0, 1),
overwrite: "auto",
immediateRender: false,
onComplete: () => animateItem(item)
});
}
}
wrapper.addEventListener("mouseenter", () => {
isHovering = true;
items.forEach(animateItem);
});
wrapper.addEventListener("mouseleave", () => {
isHovering = false;
});
This Pen doesn't use any external CSS resources.