Applying inline css transition style using a string distorts the original value. Strange

I have a CSS file that specifies a transition property as follows (vendor prefixes excluded for brevity):

transition: opacity 1s;

Now, I want to tweak the transition-delay property of each element using JavaScript to create a stagger effect. Here's how I'm doing it with jQuery:

$(element).css('transition-delay', delay + 's');

Surprisingly, this code does not directly add an inline style of transition-delay: Xs to the element. Instead, it results in:

<div style="transition: Xs;">

Although this may seem odd, it actually works correctly. The browser somehow interprets transition: Xs to mean set the transition-delay to Xs while keeping the other properties intact.

However:

If I retrieve the inline style of the element using $(element).attr('style') and then reapply it to the element like $(element).attr('style', style), the HTML appears identical, but now the transition completely overrides the other properties, effectively setting the element's transition value to all Xs ease 0s.

// Original HTML - functional
<div style="transition: Xs">

// Then this happens
var style = $(el).attr('style');
$(el).attr('style', style);

// Resulting HTML - problematic!
<div style="transition: Xs">

Demo

You can see a demonstration of this behavior on JSFiddle: http://jsfiddle.net/7vp8m/4/

What could be causing this issue?

Answer №1

After carefully writing down the question and coding a demo, I was able to uncover the solution:

The HTML style attribute does not directly control styling. Instead, we should utilize the CSSStyleDeclaration object

Although it may appear that inline styles are solely defined by what's within the style="..." HTML attribute (as I initially thought), this is not entirely accurate. In reality, all styles—inline included—are determined by an object known as CSSStyleDeclaration. The string in the style attribute simply serves to represent this object but lacks the complete set of information necessary to define a style.

This explains why setting `el.style = "width: 100px;" won't produce the desired effect. According to the MDN article on HTMLElement.style:

In most browsers, assigning a string to the read-only style property like elt.style = "color: blue;" will not work since the style attribute returns a CSSStyleDeclaration object. To set style properties correctly, you need to do this:

elt.style.color = "blue";  // Directly

var st = elt.style;
st.color = "blue";  // Indirectly

Therefore, attempting

$(el).attr('style', 'transition: Xs');
will not function as intended—this was precisely my initial stumbling block. While it can alter the underlying CSSStyleDeclaration object, the outcome might deviate from our expectations, leading to my original query.

The resolution lies in utilizing the API provided by CSSStyleDeclaration. A pivotal Stack Overflow question shed light on this matter for me: JavaScript & copy style

How to Copy a CSSStyleDeclaration:

var originalStyle = el.cloneNode().style;

We opt for cloneNode() to ensure we obtain a fresh copy of the CSSStyleDeclaration, preventing any modifications interfering with the element's inline style adjustments and future restoration efforts.

Reinstating Original Inline Style from Saved CSSStyleDeclaration

// Firstly, clear all existing style rules
for (var i = el.style.length; i > 0; i--) {
    var name = el.style[i];
    el.style.removeProperty(name);
}

// Then iterate through the original CSSStyleDeclaration 
// object and restore each property to its original value
for (var i = originalStyle.length; i > 0; i--) {
    var name = originalStyle[i];
    el.style.setProperty(name,
        originalStyle.getPropertyValue(name),
        priority = originalStyle.getPropertyPriority(name));
}

Demo

An updated version of my original demonstration implementing these methods can be found here: http://jsfiddle.net/7vp8m/11/

Answer №2

Issues arise in Chrome and the "new" Opera browsers, but not in Firefox. Maxthon experiences a hiccup where the animation stops and restarts initially, then behaves correctly.

As previously mentioned at http://jsfiddle.net/7vp8m/5 (thankfully resolved), this issue stems from setting transition delays via inline styles.

If you forcibly trigger a CSS refresh, it somewhat resolves the problem (initially pausing the animation before resuming at a slower pace): http://jsfiddle.net/7vp8m/7/

function tick() {
    [...]
    $.each($('.test'), function(i, e){
        e.style.marginLeft = x + 'px'; // Attempted with vanilla JS, same result
        e.offsetHeight; // Forces refresh, movement is still incorrect
    });
    [...]
}

The following approach also fails: http://jsfiddle.net/7vp8m/8/

$.each($('.test'), function (index, el) {
    var style = $(el).attr('style');
    style += '; transition-delay: '+delay + 's;' +
             '-webkit-transition-delay' + delay + 's;';
    $(el).attr('style', style);
    delay += 0.2;
});

This issue appears to be linked to a webkit bug concerning transition-delay, although Maxthon's similar animation halt suggests a more widespread bug.

If indeed a bug, avoiding the use of transition-delay through JavaScript is likely the best approach.

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

As the screen size shrinks, two components merge together

One issue I'm facing with my site is the component called NavPanel. This consists of two components - a back button (BackToButton) and a search field (SearchTextField). Everything looks fine on a standard screen size, but when the screen size decrease ...

What is the best way to ensure that bootstrap columns collapse in equal multiples?

I need to have 4 equal columns in each bootstrap row with only specific configurations allowed: All 4 next to each other Two above and two below All in a single column The issue is that when I adjust the screen size, sometimes I get 3 columns at the top ...

Alert: The index named "namaunit" is not defined

As a beginner in programming, I am facing an issue where my code is not working for a particular input form. Oddly enough, the same code works perfectly fine for another input form with similar structure. It's puzzling to me why it's not function ...

Tips for changing a specific item within an ng-repeat loop in AngularJS

Here is my HTML code: <tr ng-repeat="customer in customers"> <td> {{customer.customer_name}} </td> <td> {{customer.mobile}} </td> </tr> Upon executing this code, I receive 3 <tr>...</tr> blocks as s ...

Saving integer data retrieved from DynamoDB in a React Native application

I need to store a user's progress by saving a value in a DynamoDB. While storing the value is not difficult, accessing this value for use in my application has proven to be quite challenging. When using dynamoDBWrapper.getItem(params), where the para ...

Implementing custom fonts in Next.js using next-less for self-hosting

Seeking Solutions for Hosting Fonts in Next.js Application I am exploring the idea of self-hosting a font, specifically Noto, within my Next.js application that already utilizes the @zeit/next-less plugin. Should I rely on the npm package next-fonts to h ...

Issue: Query is not re-executing after navigatingDescription: The query is

On my screen, I have implemented a query as follows: export const AllFriends: React.FunctionComponent = () => { const navigation = useNavigation(); const { data, error } = useGetMyProfileQuery({ onCompleted: () => { console.log('h ...

Get the maximum width in pixels through JavaScript when it is specified in different units within the CSS

I'm looking to retrieve the max-width value in px from CSS for use in a JavaScript code. The challenge is that this value might be specified in different units in the CSS file. Any suggestions on how to achieve this using JavaScript? const element = ...

"From transitioning from a regular class to a functional component in React Native, navigating through the

I am a beginner in react native and I am struggling to convert class components into functional components. I have tried various ways to pass refs in the functional component and used hooks to manage state, but unfortunately, I haven't been successful ...

Difficulty encountered in displaying HTML within a React component

Struggling to display HTML in my React code, whenever I click 'signup' after starting the page, it shows the 'login' view instead. Could there be an issue with how I'm linking everything together? App.js class App extends Compon ...

How can we generate an array of duplicated values from an array that already contains duplicates in JavaScript?

Given an array of objects like ["a","b","a","c","d","b"], how can I efficiently retrieve an array of the duplicate elements, such as ["a","b"]? Is there a method similar to u ...

Exploring the depths of Node.js and intrigued by its scope

Currently, I'm engrossed in an ebook titled "The Node Beginner Book." It essentially consists of one extensive exercise spanning around 50 pages, covering a wide range of basics. Lately, I've been immersed in Python and have a background in PHP. ...

Start fresh with your list styling in Sass/CSS

I'm attempting to revert ul and li elements to their default styles using a specific class, but I'm encountering difficulties in doing so. I've experimented with the inherit and initial values, but they haven't proven effective. This i ...

Encountering a problem with the persistent JavaScript script

I have implemented a plugin/code from on my website: Upon visiting my website and scrolling down, you will notice that the right hand sidebar also scrolls seamlessly. However, when at the top of the screen, clicking on any links becomes impossible unless ...

Tips for smoothly transitioning from a simple transform to a rotate effect

I need help with an HTML element that needs to rotate when hovered over. Here is the code I have: The issue I'm facing is that I don't want a transition for translateX, only for the rotation. What steps should I take to achieve this? .cog { ...

Jasmine: Methods for verifying if the accurate URL is invoked during a GET request

I need to test a service function, but I'm unsure how to mock an internal service function that is called within the main function. My goal is to verify if the correct URL is being accessed. Below is the code snippet for my service: angular.module(" ...

Many mistakes encountered while trying to import web3 into app.js

Encountered 9 errors while trying to import web3 into App.js import React from "react"; import Web3 from "web3"; function App() { return ( <div className="App"> <h1>TEST APP</h1> </div> ...

When converting to JSON, objects may sometimes lose their properties

Here is a sample of my class structure: export class Patient { constructor(public id: number, public name: string, public location: string, public bedId: number, public severity: string, public trajectory: number, public vitalSigns: [GraphData[]], public ...

JavaScript for fetching JSON data

Hey everyone, I've been working on implementing user login functionality. When a user submits their login credentials, an API call is made using AJAX. Depending on whether the login credentials are correct or incorrect, I receive a response that gets ...

When multiple ajax calls are running simultaneously, the loading icon attached to a Table TD can become disordered

Whenever I click on a row in my table to fetch additional data for a drill down report, I want to display a loading icon on that row until the data is retrieved. However, if I click on a second row before the first row's data is loaded, the loading ic ...