<svg class="star" viewBox="0 0 576 512" width="100" title="star" tabindex="0">
<path d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z" />
</svg>
<svg class="star" viewBox="0 0 576 512" width="100" title="star" tabindex="0">
<path d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z" />
</svg>
body {
height: 100vh;
margin: 0;
display: grid;
place-items: center;
}
.star {
// Alternative that isn't really a boop but an interesting alternative to needing a keyframe to do waggles.
// transition: 0.6s cubic-bezier(1, -3, 0, 3);
&:hover {
// transform: rotate(20deg);
}
&:focus,
&:hover {
fill: gold;
filter: drop-shadow(0 0 3px rgba(black, 0.5));
}
&.boop {
animation: boop 0.6s forwards;
}
}
@keyframes boop {
0%,
100% {
transform: rotate(0deg);
}
25% {
transform: rotate(10deg);
}
50% {
transform: rotate(-10deg);
}
75% {
transform: rotate(10deg);
}
}
View Compiled
const stars = document.querySelectorAll(".star");
stars.forEach((star) => {
star.addEventListener("mouseenter", () => {
star.classList.add("boop");
// If the booping isn't a keyframe animation, this might still be more robust. Maybe explore options for keeping CONSTs in sync between CSS and JavaScript (custom props?)
// setTimeout(() => {
// star.classList.remove("boop");
// }, 600)
});
// This listens to any animation, but there is probably a way to check the specific animation in the `e`vent
star.addEventListener("animationend", (e) => {
star.classList.remove("boop");
});
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.