skip to Main Content

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 class="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.

2

Answers


  1. 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;
        }
      }
    
    Login or Signup to reply.
  2. 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 class="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 class="button">click me</button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search