i'm trying to create simple ripple effect. When i add classes to element newClick i expected ripple effect. Got troblued because appending class is instantly and i dont see the effect. Could you help me?
const button = document.querySelector('.button');
const handleClick = (e) => {
const newClick = document.createElement('div');
newClick.classList.add('point');
newClick.style.top = `${e.offsetY}px`;
newClick.style.left = `${e.offsetX}px`;
newClick.classList.add('active');
button.appendChild(newClick);
};
button.addEventListener('click', handleClick);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #000;
}
.button {
position: relative;
background-color: #7c1a76;
border: none;
padding: 1em 2em;
color: #fff;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
overflow: hidden;
}
.point {
position: absolute;
width: 5px;
height: 5px;
border-radius: 50%;
opacity: 1;
background-color: #fff;
transform: scale(1);
transition: transform 0.5s, opacity 0.5s;
}
.active {
transform: scale(10);
background-color: #fff;
opacity: 0;
transition: transform 0.5s, opacity 0.5s;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Button Ripple Effect</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<button >click me</button>
<script src="script.js"></script>
</body>
</html>
I spend few hours on this trouble. Why i dont see effect of transition? This is project from tutorial but i want do it on my way.
CodePudding user response:
It doesn't work because you add element to button after adding class.
To solve this problem, you must have clickContainer in button because your code create newClick element on every click event. ok?
like this
<button>
click me
<div class='clickContainer'/>
</button>
And then, follow steps below.
-create newClick element
-empty clickContainer
-append newClick element to clickContainer
-add class to newClick
Then it'll works.
And you used transition.
I think it's not suitable for this problem because after circle getting bigger, it's opacity is 0 but it keep it's size.
And also, you used 2 classes for this.
It's not good.
So I think it's easy and suitable to use animation .
I add codes below.
-script
const button = document.querySelector(".button");
const handleClick = (e) => {
if (e.target.id !== "button") return;
const clickContainer = document.querySelector("#clickContainer");
clickContainer.innerHTML = "";
const newClick = document.createElement("div");
clickContainer.appendChild(newClick);
newClick.classList.add("point");
newClick.style.top = `${e.offsetY}px`;
newClick.style.left = `${e.offsetX}px`;
};
-css
.point {
position: absolute;
width: 0px;
height: 0px;
border-radius: 50%;
background-color: #fff;
animation-name: ripple;
animation-duration: 0.5s;
animation-timing-function: ease-out;
}
@keyframes ripple {
0% {
width: 5px;
height: 5px;
opacity: 1;
transform: scale(1);
}
100% {
width: 5px;
height: 5px;
transform: scale(20);
opacity: 0;
}
}
CodePudding user response:
Transitions only happen when a CSS property changes it's value.
You are creating the <div>
, adding both classes and appending it to the DOM, all in the same frame. From the CSS perspective you're creating and adding a div.point.active
. The styles never change so there's no need to transition anything.
Delay adding .active
by a frame.
But you also never clean up so the divs for the ripples are piling up. And if you click too fast, offsetX
and offsetY
are wrong and the next ripple appears top left in the button. You should prevent the ripples catching mouse events.
requestAnimationFrame(() => {
newClick.classList.add("active");
});
setTimeout(() => newClick.remove(), 1000);
.point {
pointer-events: none;
}
const button = document.querySelector('.button');
const handleClick = (e) => {
const newClick = document.createElement('div');
newClick.classList.add('point');
newClick.style.top = `${e.offsetY}px`;
newClick.style.left = `${e.offsetX}px`;
button.appendChild(newClick);
requestAnimationFrame(() => {
newClick.classList.add("active");
});
setTimeout(() => newClick.remove(), 1000);
};
button.addEventListener('click', handleClick);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #000;
}
.button {
position: relative;
background-color: #7c1a76;
border: none;
padding: 1em 2em;
color: #fff;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
overflow: hidden;
}
.point {
position: absolute;
width: 5px;
height: 5px;
border-radius: 50%;
opacity: 1;
background-color: #fff;
transform: scale(1);
transition: transform 0.5s, opacity 0.5s;
pointer-events: none;
}
.active {
transform: scale(10);
background-color: #fff;
opacity: 0;
transition: transform 0.5s, opacity 0.5s;
}
<button >click me</button>
Or, instead of using transitions, check out the animation API
const animation = newClick.animate([
{ opacity: 1, transform: "scale(0)" },
{ opacity: 0, transform: "scale(10)" }
], 500);
animation.onfinish = () => newClick.remove();
const button = document.querySelector('.button');
const handleClick = (e) => {
const newClick = document.createElement('div');
newClick.classList.add('point');
newClick.style.top = `${e.offsetY}px`;
newClick.style.left = `${e.offsetX}px`;
button.appendChild(newClick);
const animation = newClick.animate([
{ opacity: 1, transform: "scale(0)" },
{ opacity: 0, transform: "scale(10)" }
], 500);
animation.onfinish = () => newClick.remove();
};
button.addEventListener('click', handleClick);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #000;
}
.button {
position: relative;
background-color: #7c1a76;
border: none;
padding: 1em 2em;
color: #fff;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
overflow: hidden;
}
.point {
position: absolute;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: #fff;
pointer-events: none;
}
<button >click me</button>