Disabling CSS transitions and attempting to alter the style of an HTML element using JavaScript may not consistently work as expected

Currently, I am in the process of creating an animated effect for a website that involves moving two elements' positions over time and resetting them to their original position. Only one element is displayed at a time, and the animation should run smoothly.

Unfortunately, a CSS-only solution is not feasible because the animation needs to be dynamically generated and synchronized. For the purpose of this question, I'll focus on a simplified example where a box moves to the right. The following discussion will revolve around this specific scenario unless stated otherwise.

The movement is controlled by utilizing the CSS transition property to handle the animation. To reset the element's position instantly, the transition must be removed before reapplying it when needed to start moving again immediately. However, this method doesn't seem to work as expected, which brings us to the issue at hand.

If you examine the Javascript code provided at the end of this question or on the linked JSFiddle, you'll notice that I'm attempting to remove the delay between transitions by using setTimeout. Unfortunately, this implementation introduces a 25ms delay, causing the element to intermittently remain stationary without the desired effect. Increasing the delay somewhat resolves the issue but creates a minor jitter in the animation due to its two-part nature and lack of designed delays.

While this behavior might appear to be a browser bug, testing across Chrome, Firefox 52, and the most recent version of Firefox yielded similar results. I have yet to come across any reported instances of this problem or potential solutions/workarounds. Any assistance in resolving this matter and achieving the intended functionality would be greatly appreciated. :)


Here is a link to the JSFiddle page showcasing the issue.

The relevant markup and code are also provided below:

var box = document.getElementById("box");
//Adjust this value or set it to 0 (eliminating the timeout)
//for optimal intermittent performance.
var delay = 25;

setInterval(function() {
  box.style.transition = "none";
  box.style.left = "1em";

  setTimeout(function() {
    box.style.transition = "1s linear";
    box.style.left = "11em";
  }, delay);
}, 1000);
#box {
  width: 5em;
  height: 5em;
  background-color: cyan;
  position: absolute;
  top: 1em;
  left: 1em;
}
<div id="box"></div>

Answer №1

To ensure the DOM recalculates itself before applying a new transition after resetting, you can trigger this process by reading the offset of an element. Here is an example using JavaScript:

var box = document.getElementById("box");

setInterval(function(){
      box.style.transition = "none";
      box.style.left = "1em";
      let x = box.offsetLeft; // Reading a positioning value forces DOM to recalculate all positions after changes
      box.style.transition = "1s linear";
      box.style.left = "11em";  
    }, 1000);
body {
  background-color: rgba(0,0,0,0);
}

#box {
  width: 5em;
  height: 5em;
  background-color: cyan;
  position: absolute;
  top: 1em;
  left: 1em;
}
<div id="box"></div>

For a working demo, visit jsFiddle.

By default, the DOM doesn't update immediately when properties are set; it waits until the script finishes execution. However, if you read a property after changing it, the DOM will recalculate instantly.

Without the timeout and property reading, the style.left value would first change to 1em, then abruptly switch to 11em. The transition occurs after the script finishes executing, affecting the last assigned value (11em). But by reading a position value in between changes, the transition reflects the most recent value accurately.

Answer №2

Instead of utilizing the transition for animation effects, consider using animation instead. It offers better performance and eliminates the need for a timer to monitor it.

By leveraging animation events, one can coordinate the animation as needed, such as triggering a timer to reset or modify it.

This can be achieved by setting up some components with CSS:

var box = document.getElementById("box");
box.style.left = "11em"; // initial position

box.addEventListener("animationend", animation_ended, false);

function animation_ended (e) {
  if (e.type == 'animationend') {
    this.style.left = "1em";
  }
}
#box {
  width: 5em;
  height: 5em;
  background-color: cyan;
  position: absolute;
  top: 1em;
  left: 1em;
  animation: move_me 1s linear 4;
}
@keyframes move_me {
  0% { left: 1em; }
}
<div id="box"></div>

Or go for a completely script-based approach:

var prop = 'left', value1 = '1em', value2 = '11em'; 

var s = document.createElement('style');
s.type = 'text/css';
s.innerHTML = '@keyframes move_me {0% { ' + prop + ':' + value1 +' }}';
document.getElementsByTagName('head')[0].appendChild(s);

var box = document.getElementById("box");
box.style.animation = 'move_me 1s linear 4';
box.style.left = value2; // initial position

box.addEventListener("animationend", animation_ended, false);

function animation_ended (e) {
  if (e.type == 'animationend') {
    this.style.left = value1;
  }
}
#box {
  width: 5em;
  height: 5em;
  background-color: cyan;
  position: absolute;
  top: 1em;
  left: 1em;
}
<div id="box"></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

Navigate the user to various pages in a Node.js application based on login status

Looking for guidance on a login system within my application? I need to redirect users based on their roles. Below is the code for the login controller, along with node.js snippets and the login HTML page. Any help would be appreciated. Login.html - < ...

What could be causing the search function of the datatable to be hidden?

I am experiencing some difficulties with the code I have. My goal is to incorporate search functionality and pagination into my table. Unfortunately, it does not seem to be working as expected. Below is a snippet of the script located in the header section ...

What is the preferred workflow for client-side modules: (Browserify + npm + gulp) or (RequireJS + Bower + gulp)?

As I delve into various client-side Javascript modules workflows for my current Node.JS Express project, I find myself torn between Browserify + npm + gulp and RequireJS + Bower + gulp. While I lean towards CommonJS due to its syntax, the idea of sharing ...

How can I use a JavaScript function to remove an element from a PHP array?

Imagine I have a PHP session array: $_SESSION[MyItems]=Array('A'=>"Apple", 'B'=>"Brownie", 'C'="Coin")) which is utilized to showcase items on a user's visited page. I want the user to have the ability to remove o ...

Guide to displaying a custom HTML tag

In this example: <?php $html='<p style="color:#eee;"> Test content 1. </p> <p dir="LTR" style="color:#f00;"> <span>Test content 2.</span> </p> <p style="color:#000;"> Test content 3. </p>' ?> ...

My image is being cropped on larger screens due to the background-size: cover property

I am currently in the process of designing a website with a layout consisting of a Header, Content, and Footer all set at 100% width. To achieve a background image that fills the screen in the content section, I utilized CSS3 with background-size:cover pr ...

Positioning social media icons directly below the Avatar component

I've been working on aligning my social media icons under the Avatar component. Despite trying multiple methods to center them in the JSS, I haven't had much success. I attempted different approaches but couldn't achieve the desired alignmen ...

Creating vibrant squares using HTML and CSS

My objective is to incorporate 3 input options for selecting the color, size, and amount of cubes. The image below showcases my peer's final project, but unfortunately, he refused to share the code with me. We were given a basic template to begin with ...

Run the function after the onclick function has finished executing

I'm currently working on diagnosing an issue with this application. There is an anchor tag that contains the following code: onclick="javascript: return ShowItemDiscussion();" This code is located in a separate JavaScript file. I am attempting to ...

Loading files using $scriptjs or any other asynchronous loader allows for seamless integration of external resources

Imagine I have developed an AngularJS application that lazy loads controller files (using $scriptjs) and all dependencies when the user navigates to a specific route. This application consists of 3 routes: A, B, and C. My question is: if the user navigate ...

Exploring the concept of passing 'this' as a parameter in JavaScript

<button type="button" aria-haspopup="dialog" aria-controls="b" onclick="openLayer($('#b'))"> button</button> <div role="dialog" id="b"><"button type="button">close<"/button></div> function openLayer(target){ ...

executing functions that return a JSX component within the render method

In an effort to enhance readability, I am striving to condense the length of the render() method by utilizing class methods that contain isolated JSX elements. A snag arises when attempting to apply this technique to more than one JSX element. Despite en ...

What is the best way to combine two responses and then convert them into a promise?

When making two calls, the firstCallData prints data fine. However, when I use + to merge the responses, it returns me the following Response. What is a better approach to achieve this task? main.ts let data = await this.processResponse(__data.Detail ...

Tips for How to Put a Delay on Ajax Requests and Display a Progress Bar During Loading

I am using checkboxes in the sidebar. When a user selects a checkbox from the sidebar, it displays the post normally. Is there a way to add a progress bar to delay the Ajax result? This is my Ajax code: <script> jQuery(document).ready(function($){ ...

Transferring information submitted in a form to a service using AngularJS

Trying to implement a shopping cart app where I need to pass an object into a service function using Angular. Following advice from another post, but encountering an unprovided error and a strange syntax error on page load. The issues seem to be originatin ...

React is unable to identify the property that was passed to a styled-component in Material UI

Custom Styled Component Using Material-UI: import { Typography } from '@material-ui/core'; const CustomText = styled(Typography)<TextProps>` margin-bottom: 10px; color: ${({ textColor }) => textColor ?? textColor}; font-size: ${( ...

Encountered a MySQL error while attempting to insert an image into the database

I have a task to work on a website where users can upload product images that will be stored in a MySQL database. The code for my HTML form is: <FORM action="testimage1.php" ENCTYPE="multipart/form-data" method="post"> <div st ...

Closing the Bootstrap Dropdown Menu

I have a dropdown menu in my bootstrap project. I am looking for a way to make the menu close when I click on one of the menu items, without refreshing the page. The links function like an ajax request model, ensuring that the page does not reload. <l ...

The slider thumb is not showing up properly on Microsoft Edge

Hey there! I'm experiencing an issue with the range slider's thumb display in Microsoft Edge. It appears to be positioned inside the track rather than outside as intended. Take a look at this snapshot for clarification: https://i.stack.imgur.co ...

Change object values to capital letters

Upon retrieving myObject with JSON.stringify, I am now looking to convert all the values (excluding keys) to uppercase. In TypeScript, what would be the best way to accomplish this? myObj = { "name":"John", "age":30, "cars": [ { "name":"Ford", ...