How to Build a Stunning Like‑Button Particle Animation with Pure CSS
This tutorial walks through creating a eye‑catching like‑button effect using only CSS and a bit of JavaScript, covering parabolic particle motion, an optional oblique bounce, batch generation of random emojis, a +1 number animation, and a brief note on canvas alternatives.
1. CSS Parabolic Motion
The effect consists of two animations: a particle following a parabolic trajectory and a number scaling animation. A parabolic motion is a combination of constant horizontal speed and constant vertical acceleration. Using two nested divs, the horizontal movement uses a linear timing function while the vertical movement uses a cubic‑bezier curve to simulate acceleration.
<div class="ball-x">
<div class="ball-y"></div>
</div>Key CSS:
.ball-x { animation-timing-function: linear; }
.ball-y { animation-timing-function: cubic-bezier(0.55,0,0.85,0.36); }
@keyframes custom-x { 100% { transform: translateX(300%); } }
@keyframes custom-y { 100% { transform: translateY(300%); } }2. CSS Oblique Motion
To add an upward launch and a slight bounce, the cubic‑bezier curve is adjusted so the second control point becomes negative, creating a reverse acceleration phase.
.ball-y { animation-timing-function: cubic-bezier(0.56,-1.35,0.85,0.36); }This produces a subtle rebound that more closely resembles a real projectile.
3. Batch Generation with JavaScript
One particle looks static, so the tutorial shows how to generate many random particles on each click. JavaScript creates a document fragment, picks a random subset of emojis, and assigns CSS variables --x (horizontal offset) and --d (delay) to each dot. An animationend listener removes finished dots.
function createDots(emojis) {
const fragment = document.createDocumentFragment();
const randomEmojis = emojis.slice(0, Math.ceil(Math.random()*emojis.length))
.sort(() => Math.random() - .5);
randomEmojis.forEach(emoji => {
const dot = document.createElement('div');
dot.className = 'custom-tips-dot';
dot.setAttribute('emoji', emoji);
dot.style.setProperty('--d', `${Math.random()*0.2}s`);
dot.style.setProperty('--x', `${(Math.random()-0.5)*1000}%`);
fragment.appendChild(dot);
dot.addEventListener('animationend', () => {
dot.parentNode?.removeChild(dot);
});
});
return fragment;
}
document.addEventListener('click', ev => {
const {clientX, clientY} = ev;
document.body.style.setProperty('--left', `${clientX}px`);
document.body.style.setProperty('--top', `${clientY}px`);
const tips = document.createElement('div');
tips.className = 'custom-tips';
tips.style.setProperty('--left', `${clientX}px`);
tips.style.setProperty('--top', `${clientY}px`);
const dots = createDots(['🎉','😘','🎊','🤡','🥳','🤪','💗']);
tips.appendChild(dots);
document.body.appendChild(tips);
});4. "+1" Number Animation
The numeric animation is a simple scale‑and‑opacity change. The HTML element carries a num attribute, and a ::before pseudo‑element displays "+" followed by that number.
<div class="custom-num" num="1"></div>Key CSS and keyframes:
.custom-num { position:absolute; left:0; top:0; display:flex; width:2em; height:2em; font-size:2em; color:#fff; justify-content:center; align-items:center; margin-left:-1em; margin-top:-2em; font-weight:bold; text-shadow:4px 4px 0 rgba(255,0,0,0); transform: translate(var(--left), var(--top)); }
.custom-num::before { content:'+' attr(num); opacity:0; animation: count-shark 1s var(--d,0s); }
@keyframes count-shark {
0%,100% { opacity:0; transform:scale(.4); }
30%,70% { opacity:1; transform:scale(1); }
}JavaScript increments the number by removing the old element and inserting a new one with an increased num attribute.
function createNum() {
const current = document.querySelector('.custom-num');
let num = 1;
if (current) {
num = parseInt(current.getAttribute('num')) + 1;
current.remove();
}
const numDiv = document.createElement('div');
numDiv.className = 'custom-num';
numDiv.setAttribute('num', num);
numDiv.addEventListener('animationend', () => numDiv.remove());
return numDiv;
}5. Canvas Alternative
For many particles, canvas offers better performance, though it may be less beginner‑friendly. The article mentions the Canvas Confetti library as a ready‑made solution for confetti‑style effects.
All the pieces combined reproduce the eye‑catching like‑button animation shown at the beginning of the article.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Cultivation Path
Focused on sharing practical tech content about TypeScript, Vue 3, front-end architecture, and source code analysis.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
