Creating motion in recently added elements using varied keyframe settings

I'm currently working on a simple animation project. The goal is to create a circle that appears and moves upwards when you click inside the blue container. I managed to find out how to incorporate JavaScript values into keyframes, but the issue is that it's affecting all objects instead of just the newly created one. If you try running the code snippet and click in different areas, you'll see what I mean.

I came across an amazing solution using the Raphael library, but as a beginner, I'd like to achieve something similar using JavaScript. Is it actually possible? And if so, how?

var bubble = {
    posX: 0,
    posY: 0,
    size: 0
  };

var aquarium = document.getElementById("container");

var ss = document.styleSheets;
var keyframesRule = [];
function findAnimation(animName) { //function to find keyframes and insert replace values in them
  for (var i = 0; i < ss.length; i++) {
    for (var j = 0; j < ss[i].cssRules.length; j++) {
      if (window.CSSRule.KEYFRAMES_RULE == ss[i].cssRules[j].type && ss[i].cssRules[j].name == animName) {
        keyframesRule.push(ss[i].cssRules[j]);
      }
    }
  }
  return keyframesRule;
}


function changeAnimation (nameAnim) {  //changing top value to cursor position when clicked
  var keyframesArr = findAnimation(nameAnim);
  for (var i = 0; i < keyframesArr.length; i++) {
    keyframesArr[i].deleteRule("0%");
    keyframesArr[i].appendRule("0% {top: " + bubble.posY + "px}");
  }
}


function createBubble(e) {
  "use strict";
  bubble.posX = e.clientX;
  bubble.posY = e.clientY;
  bubble.size = Math.round(Math.random() * 100);
  var bubbleCircle = document.createElement("div");
  aquarium.appendChild(bubbleCircle);
  bubbleCircle.className = "bubble";
  var bubbleStyle = bubbleCircle.style;
  bubbleStyle.width = bubble.size + "px";
  bubbleStyle.height = bubble.size + "px";
  bubbleStyle.borderRadius = (bubble.size / 2) + "px";
  //bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
  bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
  changeAnimation("moveUp");
  bubbleCircle.className += " animate";
}

aquarium.addEventListener("click", createBubble);
//console.log(bubble);
body {
  background-color: red;
  margin: 0;
  padding: 0;
}

#container {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 80px;
  left: 0;
  background-color: rgb(20,255,200);
}

#surface {
  width: 100%;
  height: 40px;
  position: fixed;
  top: 40px;
  opacity: 0.5;
  background-color: rgb(250,250,250);
}

.bubble {
  position: fixed;
  border: 1px solid blue;
}

.animate {
  animation: moveUp 5s linear;//cubic-bezier(1, 0, 1, 1);
  -webkit-animation: moveUp 5s linear;//cubic-bezier(1, 0, 1, 1);
}


@keyframes moveUp{
  0% {
    top: 400px;
  }
  100% {
    top: 80px;
  }
}

@-webkit-keyframes moveUp{
  0% {
    top: 400px;
  }
  100% {
    top: 80px;
  }
}
<body>
  <div id="container">
  </div>
  <div id="surface">
    
  </div>
</body>

Answer №1

Here is a potential solution that I came up with:

  • First, I removed the unnecessary functions changeAnimation() and findAnimation() as they are not required.
  • I updated the keyframe to only include the styling for 100%:

    @keyframes moveUp { 100% {top: 80px;} }

  • I adjusted the positioning of the new bubble by assigning the top value based on the clientY property.

  • After 5 seconds, I set the top property of the bubble to match the offset of the #container (which is 80px). This ensures that the bubble remains in place after the animation completes.

var bubble = {
  posX: 0,
  posY: 0,
  size: 0
};

var aquarium = document.getElementById("container");

function createBubble(e) {
  "use strict";
  bubble.posX = e.clientX;
  bubble.posY = e.clientY;

  bubble.size = Math.round(Math.random() * 100);
  var bubbleCircle = document.createElement("div");
  aquarium.appendChild(bubbleCircle);
  bubbleCircle.className = "bubble";
  var bubbleStyle = bubbleCircle.style;
  bubbleStyle.width = bubble.size + "px";
  bubbleStyle.height = bubble.size + "px";
  bubbleStyle.borderRadius = (bubble.size / 2) + "px";
  bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
  bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
  bubbleCircle.className += " animate";

  // Adjusting top position after 5 seconds to maintain bubble's position 
  // once the animation is complete
  (function(style) {
    setTimeout(function() {
      style.top = '80px';
    }, 5000);
  })(bubbleStyle);
}

aquarium.addEventListener("click", createBubble);
body {
  background-color: red;
  margin: 0;
  padding: 0;
}

#container {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 80px;
  left: 0;
  background-color: rgb(20, 255, 200);
}

#surface {
  width: 100%;
  height: 40px;
  position: fixed;
  top: 40px;
  opacity: 0.5;
  background-color: rgb(250, 250, 250);
}

.bubble {
  position: fixed;
  border: 1px solid blue;
}

.animate {
  animation: moveUp 5s linear;
  /*cubic-bezier(1, 0, 1, 1);*/
  -webkit-animation: moveUp 5s linear;
  /*cubic-bezier(1, 0, 1, 1);*/
}

@keyframes moveUp {
  100% {
    top: 80px;
  }
}

@-webkit-keyframes moveUp {
  100% {
    top: 80px;
  }
}
<body>
  <div id="container"></div>
  <div id="surface"></div>
</body>

The issue with your original code was that it globally impacted all bubbles by altering the @keyframes moveUp.

Answer №2

Your code may have a flaw in updating keyframes that affect all bubbles. To address this, I experimented with using transition and adjusting the top position after adding the element to the DOM for animation.

The challenge lies in timing the addition of the element to the DOM correctly. Despite trying MutationObserver, it seemed to trigger before the element was actually rendered. Resorting to a timeout workaround mimics this waiting period, but there may be more efficient methods available. I'm open to suggestions on improving this process.

var bubble = {
  posX: 0,
  posY: 0,
  size: 0
};

var aquarium = document.getElementById("container");

function createBubble(e) {
  "use strict";
  bubble.posX = e.clientX;
  bubble.posY = e.clientY;
  bubble.size = Math.round(Math.random() * 100);

  var bubbleCircle = document.createElement("div");
  aquarium.appendChild(bubbleCircle);

  bubbleCircle.classList.add("bubble");
  var bubbleStyle = bubbleCircle.style;

  bubbleStyle.width = bubble.size + "px";
  bubbleStyle.height = bubble.size + "px";
  bubbleStyle.borderRadius = (bubble.size / 2) + "px";
  bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
  bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";

  setTimeout(function() {
    bubbleCircle.classList.add("moveUp");
  }, 50);
}

aquarium.addEventListener("click", createBubble);
body {
  background-color: red;
  margin: 0;
  padding: 0;
}

#container {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 80px;
  left: 0;
  background-color: rgb(20, 255, 200);
}

#surface {
  width: 100%;
  height: 40px;
  position: fixed;
  top: 40px;
  opacity: 0.5;
  background-color: rgb(250, 250, 250);
}

.bubble {
  position: fixed;
  border: 1px solid blue;
  transition: 5s;
}

.moveUp {
  top: 80px !important;
}
<body>
  <div id="container">
  </div>
  <div id="surface">

  </div>
</body>

I opted for using the classList object over className += ... for increased reliability.

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

The text-overflow property with ellipsis functionality appears to be malfunctioning in Internet Explorer when applied to input elements, yet functions

Having an issue with the MS IE (version 11) when using the text-overflow: ellipsis; property for an input field. It appears that this specific property is not working properly in this browser. If anyone has any suggestions or solutions, it would be greatl ...

The result of the $.post() request is back

In my current code, I am using a jQuery $.post function like this: $.post('/test', json_data, function(data) { result = data }); This function is being used in a validation process where the return value (data) contains either true or false ...

Adjust the size of an image with jquery without relying on server-side scripts

I am currently developing an application for Samsung Tizen TV that displays images from live URLs. On one screen, there are approximately 150 images, each with a size of around 1 MB and a resolution of 1920 by 1080. Navigating between these items has bec ...

Modify the appearance of a Javascript file that is parsing data from a text file

I am working on an HTML project where I have a JavaScript file that reads from a text file. Currently, the text from the file is displaying in my HTML file, but I would like to style it using CSS. Can anyone provide guidance on how to achieve this? I am st ...

Modify mesh in three.js scene

Is there a way to dynamically change a mesh in a group triggered by a button click? I am loading an external .obj file: loader.load( obj, function ( object ) { createScene( object, mod.tipo, pid, cor.replace("#","0x") ); }); and adding it to a gro ...

Consistently maintaining a uniform distance between icons and the border box is essential

I am working on a team overview for a company where data such as name, job title, and information are fetched from the database. Due to varying lengths of information, the icons are not aligning properly in one line. https://i.sstatic.net/cEmKj.png Does ...

Creating an animated sidebar that moves at a different speed than the rest of the

I have a layout with a large sidebar and small content, where the "Fixed part" refers to sticky positioning. I'm attempting to achieve this using scrollTop, but the sidebar is causing some issues like this: The code should only be executed when the ...

Performing HTTP requests within a forEach loop in Node.js

I have a collection of spreadsheets containing data that needs to be uploaded through an API. Once the data is extracted from the spreadsheet, I create individual objects and store them in an array. My initial approach involved iterating over this array, ...

Launching a Popup in ASP.NET followed by a Redirect

I have a unique custom CSS/HTML popup lightbox along with a form that contains a button. My objective is, upon clicking the button: to open the popup followed by using Thread.Sleep and finally carry out a Response.Redirect to a different page. Do you th ...

Why is the alignment of my page titles off?

In my admin component, I have a menu and a header. https://i.sstatic.net/oGJMR.png However, when I create a new page like the currency page, the title appears at the bottom instead of the top. Why is that? I believe there might be an issue with the admi ...

Post Request to Express API does not produce any output

Today, I encountered an issue while trying to create a JWT authentication API in Express. When I send a POST request with Postman, it only returns {}. Below is the code for server.js: const express = require("express"); const mongoose = require("mongoos ...

Directus | The Revision is not being updated when a collection is created in Flows

I am currently working with the latest version 9 of Directus. I have set up a Data Model called "Article" with fields for title and Random_order. https://i.sstatic.net/3JcZ4.png https://i.sstatic.net/bRpBF.png I have created a Directus flow that upda ...

If the variable is not defined, then utilize a different one

There are two scopes: $scope.job and $scope.jobs. I also have a variable called job; If $scope.job is undefined, I want $scope.jobs to be assigned to the job variable using the following code: var job = $scope.jobs. However, if $scope.job is defined, the ...

Executing a function when clearing an autocomplete textfield in Material-UI

Currently, I am working with a material-ui autocomplete text field in order to filter a list. My goal is to have the list repopulate back to its original form when the user deletes the text and presses the enter key. After my research, it seems like the ...

Ways to adjust the color of a navbar link according to the current page you are visiting?

I'm looking to implement a feature on my website where the area around the nav-link darkens when someone navigates to a certain page, making it easier for them to see which page they are currently on. I am working with Bootstrap v4.3.1 and Razor Pages ...

Different approach to loading Handlebars template instead of using fs.readFile with res.json in Express

In my efforts to create a straightforward live API endpoint (using res.json()) within an Express 4 application that merges Handlebars templates with data and sends back a string for client-side HTML replacement, I've encountered a challenge. The curr ...

Visitors may not immediately notice the CSS/JavaScript modifications in their browsers

Currently, I am working on a web application utilizing Spring MVC and Hibernate, deploying it on Apache Tomcat 8. Most of my users access the app using Google Chrome. However, I have encountered an issue where whenever I update the CSS or JavaScript files ...

What is the best way to display the press down (:active) effect before releasing the finger?

Is there a way to display the :active CSS effect on mobile devices while the user's finger is still touching the screen? I have noticed that the effect only shows after the finger is lifted, but I prefer the way Amazon's buttons display this effe ...

Creating a stationary menu on the header that overlaps both the header and content on mobile browsers

I'm currently in the process of developing a website, but I've hit a snag that I can't seem to figure out. You can view the website at . I'm focusing on mobile-first design, so for the best view, try shrinking the browser screen. When ...

Automatically adjusting the height of a Bootstrap carousel as the token-input list grows in size

I am working on a carousel that functions as a form. One of the carousel items contains a multi-select box. How can I automatically increase the height of only that specific carousel item as the height of the multi-select box increases? The first image sh ...