I think just writing out the question and coding that demo really helped me to find the answer:
The HTML style
attribute is not the actual style. We need to use the CSSStyleDeclaration object
Although it seems that the inline style is as simple as whatever is contained in the style="..."
HTML attribute (as I had assumed), it turns out that this is not the case. Behind the scenes, inline styles (and all other styles) are actually defined by an object called CSSStyleDeclaration. The string contained in the style
attribute only represents this object, but does not contain all the information needed to define a style.
This is why setting `el.style = "width: 100px;" does not work. From the MDN article on HTMLElement.style:
Except in Opera, styles can not be set by assigning a string to the (read only) style property, as in elt.style = "color: blue;". This is because the style attribute returns a CSSStyleDeclaration object. Instead, you can set style properties like this:
elt.style.color = "blue"; // Directly
var st = elt.style;
st.color = "blue"; // Indirectly
So this shows us why doing $(el).attr('style', 'transition: Xs');
will not work as expected - and this is exactly what I was running into. Doing so will modify the underlying CSSStyleDeclaration object, but not always in the way we want it to (hence my original question).
The solution is therefore to use the API provided by CSSStyleDeclaration. The following SO question proved crucial to me understanding this issue: JavaScript & copy style
Copying a CSSStyleDeclaration:
var originalStyle = el.cloneNode().style;
Here we are using the cloneNode() method because otherwise (if we just get el.style) the CSSStyleDeclaration object is copied by reference, which is not what I want since I will be changing the element's inline style and then I want to restore the original style later. Cloning the element first allows us to get a "fresh" copy of the CSSStleDeclaration that will not change when we alter the inline styles of our element el
.
Replacing current inline style with the saved CSSStyleDeclaration
// first we need to delete all the style rules
// currently defined on the element
for (var i = el.style.length; i > 0; i--) {
var name = el.style[i];
el.style.removeProperty(name);
}
// now we loop through the original CSSStyleDeclaration
// object and set 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
Here is an update of my original demo that implements the above methods: http://jsfiddle.net/7vp8m/11/