Experience the seamless transition of new CSS animations

I designed a basic HTML game where a moving box disappears when clicked on. However, the animation that follows does not originate from the click location but rather from the original position.

I believe the remove @keyframes at 0% should be based on the click location, but I have been unable to figure out how to achieve this.

Any suggestions on how I can accomplish this?

  (function () {
    const charactersGroup = document.querySelectorAll('.character');
    const stage = document.querySelector('.stage')
    const clickHandler = (e) => {
      const target = e.target;
      if (target.classList.contains('character')) {
        target.classList.remove(`f${target.dataset.id}`);
        target.classList.add('f0');
        target.classList.add('remove');

        setTimeout(() => { stage.removeChild(target) }, 2000);
      }
    }
    stage.addEventListener('click', clickHandler);
  }());
.stage {
      overflow: hidden;
      position: relative;
      background: #eeeeaa;
      width: 40vw;
      height: 20vw;
    }

    @keyframes moving {
      0% {
        transform: translateX(0);
      }
      100% {
        transform: translateX(30vw);
      }
    }
    @keyframes remove {
      0% {
        transform: translate(0);
      }
      100% {
        transform: translateY(60vw);
      }
    }
    .character {
      position: absolute;
      width: 50px;
      height: 50px;
      background-repeat: no-repeat;
      background-position: 50% 50%;
      background-size: contain;
      animation: moving infinite alternate;
    }
    .remove {
      animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
    }
    .f0 {
      background-color: black;
      animation-duration: 2s;
    }
    .f1 {
      left: 5%;
      bottom: 5%;
      animation-duration: 2s;
      background-color: red;
    }
<div class="stage">
  <div class="character f1" data-id="1"></div>
</div>

Answer №1

Modify the primary animation to utilize the left property instead of translate, then attach both animations to the element from the start. To activate the transition between the two animations, toggle the animation-play-state when adding the remove class.

(function() {
  const charactersGroup = document.querySelectorAll('.character');
  const stage = document.querySelector('.stage')
  const clickHandler = (e) => {
    const target = e.target;
    if (target.classList.contains('character')) {
      target.classList.add('remove');

      setTimeout(() => {
        stage.removeChild(target)
      }, 2000);
    }
  }
  stage.addEventListener('click', clickHandler);
}());
.stage {
  overflow: hidden;
  position: relative;
  background: #eeeeaa;
  width: 40vw;
  height: 20vw;
}

@keyframes moving {
  100% {
    left:calc(95% - 50px);
  }
}

@keyframes remove {
  50% {
    transform: translateY(-30vh);
  }
  100% {
    transform: translateY(60vw);
  }
}

.character {
  position: absolute;
  width: 50px;
  height: 50px;
  background:red;
  left: 5%;
  bottom: 5%;
  animation: 
     moving 2s infinite alternate,
     remove 1s cubic-bezier(.68, -0.55, .27, 1.55) forwards paused;
}

.remove {
  animation-play-state:paused,running;
  background: black;
}
<div class="stage">
  <div class="character f1" data-id="1"></div>
</div>

Answer №2

If your situation involves handling a large number of these boxes with complexity, it's advisable to manage everything using pure JS. However, I attempted to make this functional with minimal adjustments in both JS and CSS.

I have included explanatory comments in the new JS code.

Additionally, I took the initiative to create a distinct class called moving for the animation feature so that it can be removed upon clicking.

(function () {
    const charactersGroup = document.querySelectorAll('.character');
    const stage = document.querySelector('.stage')
    const clickHandler = (e) => {
      const target = e.target;
      if (target.classList.contains('character')) {
        target.classList.remove(`f${target.dataset.id}`);
        target.classList.add('f0');
        // remove the moving animation
        target.classList.remove('moving');
        // Get offsetWidth which is the half of width to substract later while calculating left for the target i.e our box.
        const offsetWidth  = parseInt(getComputedStyle(target).width)/2;
        // e.clientX gives us the x coordinate of the mouse pointer
        // target.getBoundingClientRect().left gives us left position of the bounding rectangle and acts as a good offset to get the accurate left for our box.
        target.style.left = `${e.clientX -target.getBoundingClientRect().left - offsetWidth}px`;
       target.classList.add('remove');
     setTimeout(() => { stage.removeChild(target) }, 2000);
      } 
    }
    stage.addEventListener('click', clickHandler);
  }());
.stage {
      overflow: hidden;
      position: relative;
      background: #eeeeaa;
      width: 40vw;
      height: 20vw;
    }

    @keyframes moving {
      0% {
        transform: translateX(0);
      }
      100% {
        transform: translateX(30vw);
      }
    }
    @keyframes remove {
      0% {
        transform: translate(0vh);
      }
      100% {
        transform: translateY(60vw);
      }
    }
    .character {
      position: absolute;
      width: 50px;
      height: 50px;
      background-repeat: no-repeat;
      background-position: 50% 50%;
      background-size: contain;
    }
    
    .moving{
      animation: moving infinite alternate;
    }
    .remove {
      animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
    }
    .f0 {
      background-color: black;
      animation-duration: 2s;
    }
    .f1 {
      left: 5%;
      bottom: 5%;
      animation-duration: 2s;
      background-color: red;
    }
<div class="stage">
  <div class="character moving f1" data-id="1"></div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be causing my array to be undefined upon the creation of a Vue component?

I'm struggling to comprehend why my array is showing as undefined in my Vue component. The issue arises in the following scenario: The SelectCategories.vue component uses the router to navigate to the Quiz.vue component. Here, I utilize props to tran ...

TypeScript error: Cannot find property 'propertyName' in the 'Function' type

I encountered an issue with the TypeScript compiler when running the following code snippet. Interestingly, the generated JavaScript on https://www.typescriptlang.org/play/ produces the desired output without any errors. The specific error message I recei ...

Exploring the dynamic changes in user authentication state with Angular Fire subscriptions

At the moment, I have been listening to authentication state changes in my ngOnInit method of my AppComponent: export class AppComponent implements OnInit { constructor(public fireAuth: AngularFireAuth) { } ngOnInit(): void { this.fireAuth.auth ...

A dynamic input field will appear on the page following the closing </form> tag

I encountered an unusual situation where upon clicking a button with the id #fusk, dynamic elements are added. Here is the code snippet: $('#imgc').append( "<div class='divi'>" + "<input type='hidden' name=' ...

Clicking on Fixed Positioning triggers a reset

When I activate the sidebar by clicking the menu button, it remains fixed in position until the first scroll. However, if I interact with the sidebar by clicking on it, the button resets and goes back to the top of the page. This issue seems to only occur ...

IonTabButton not responding to onClick events

Currently, I am utilizing the Ionic 5 CSS library in combination with React. I found that IonTabButtons have a more appealing style compared to IonButtons because IonTabButton allows for text below the Icon. In the screenshot provided, all icons are displ ...

React - Updating the document title upon user navigation away from the current page

I have encountered a challenge and I am seeking guidance on how to resolve it. Throughout our website, all pages have a default title based on our index.html file: <html lang="en"> <head> <title>My Page Title</title> ...

The Laravel function is not returning as expected on the server

I'm facing an issue with my Laravel project. When the validator fails, the return back function works fine on localhost but on the server it redirects to the root URL. Can anyone help me resolve this problem? Here is my controller code: public functi ...

How to Embed a Javascript (jquery) Variable within a JSON Object

I have searched everywhere for a "simple answer" to this problem, but unfortunately, I cannot find a solution that aligns with my understanding of JSON and jQuery. Perhaps I am too much of a beginner in JSON to accurately formulate the right question (and ...

Custom Jquery function is failing to position divs correctly within ajax-loaded content

I recently coded a custom function that efficiently positions absolute divs within a container by calculating top positions and heights: $.fn.gridB = function() { var o = $(this); //UPDATED from var o = $(this[0]); o.each(function() { var ...

Issue with WebRTC, socket.io, and node.js: Unable to access the property 'emit' as it is undefined

Currently, I am in the process of creating a webrtc video app. Within the client code section, the following lines are present: getUserMedia(constraints, handlemedia, errorhandle); constraints = {video: true}; function handlemedia(stream){ //other act ...

`Populating fields in Firebase``

I am currently in the process of transitioning from a Mongoose + Express app to using Firebase + Express. However, I am facing some challenges with populating related fields similar to how it is done in Mongoose. Is there a more efficient way to achieve th ...

Using async/await does not execute in the same manner as forEach loop

Here is a code snippet that I have been working with. It is set up to run 'one' and then 'two' in that specific order. The original code listed below is functioning correctly: (async () => { await runit('one').then(res ...

The contenteditable div's selectAll feature doesn't function properly when it gains focus

I'm working with divs in a table structure and here's an example: <div contenteditable="true" onfocus="document.execCommand('selectAll',false,null)">Something</div> Clicking on a div to focus works perfectly, selectin ...

Changing font color of a selected item in Material-UI's textview

I have a select textview in my react app and I am wondering how to change the font color after selecting an item from this textview. <div> <TextField id="standard-select-currency" select fullWidth l ...

Tips for aligning a div underneath another div in a centered position

I am attempting to align .rij_lessenrooster below .rij_weekdagen so that it is centered under each day. The teacher advised me to create a column and then try it, but it did not resolve the alignment issue. The .rij_weekdagen consistently appears off to th ...

Utilizing an NPM package in your project

Trying to incorporate a node module called "tagify" into my node.js application has been challenging. Following the instructions in the package's readme file (https://www.npmjs.com/package/@yaireo/tagify#installation), I executed the setup steps as ou ...

Encountering a router issue when trying to export using Express middleware

New to this and encountering a router error when trying to export in Express. How can I resolve this issue for both the router and the mongo model? Hoping for a successful export process in both the router and the mongo model. ...

What is the proper way for a browser to handle a srcset attribute containing the same path twice?

When the same path or similar sized images with different pixel density descriptors are used, how does the specification address it? An interesting case study is observed when viewing an image in desktop browsers like Windows Firefox 82.0b2 and Chrome 85. ...

Leveraging retrieved API data to generate numerous components

Hey there! I'm new to JavaScript and I'm working on creating a todo list with fake ToDos from jsonplaceholder using Fetch. My goal is to fetch five different ToDos and display them in separate list items within my list. However, I'm encounte ...