An element has a JavaScript style
object which contains the different names and values of CSS styles. I'd like to trigger a function every time this object changes without use of polling. Is there any way to do this in a way that is cross-browser compatible and would work reliably with third party code (because let's say you're providing a drop-in script)? Binding a JavaScript event like DOMAttrModified
or DOMSubtreeModified
won't suffice because they don't work in Chrome.

- 5,753
- 72
- 57
- 129

- 3,940
- 9
- 42
- 68
-
http://stackoverflow.com/questions/4561845/firing-event-on-dom-attribute-change – ShaggyInjun Jun 03 '12 at 05:32
-
I have an answer, but, are you targeting ancient browsers? or just major browsers? – Sepehr Jun 13 '12 at 08:34
-
1@3p3r I am targeting older versions of browsers as well but I'd definitely be interested in a solution that only targets newer versions – user730569 Jun 13 '12 at 14:24
-
@3p3r But no I don't care about old browsers that no one uses, like Konqueror or whatever... – user730569 Jun 13 '12 at 14:26
-
@user730569 I've [already answered](http://stackoverflow.com/a/11011106/1055628), use `getter` and `setter` for maximum performance – Sepehr Jun 13 '12 at 16:07
-
why dont you use the change event of Jquery. and if you little workout more, you will find a live event of jquery which pretty much does what you need. Regards – Murtaza Khursheed Hussain Jun 14 '12 at 06:50
6 Answers
Edit 4: Live Demo
$(function() {
$('#toggleColor').on('click', function() {
$(this).toggleClass('darkblue');
}).attrchange({
trackValues: true,
callback: function(event) {
$(this).html("<ul><li><span>Attribute Name: </span>" + event.attributeName + "</li><li><span>Old Value: </span>" + event.oldValue + "</li><li><span>New Value: </span>" + event.newValue + "</li></ul>");
}
});
});
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
}
#toggleColor {
height: 70px;
width: 300px;
padding: 5px;
border: 1px solid #c2c2c2;
background-color: #DBEAF9;
}
#toggleColor span {
font-weight: bold;
}
#toggleColor.darkblue {
background-color: #1A9ADA;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://meetselva.github.io/attrchange/javascripts/attrchange.js"></script>
<p>Click below div to toggle class darkblue.</p>
<div id="toggleColor"></div>
Edit 3: I have put all this together as a plugin that can be downloaded from git attrchange and here is the demo page.
Edit 2:
- Fix for propertName in IE7 & IE8
Edit 1:
- Handle multiple elements
- Ordered the conditions as MutationObserver, DOMAttrModified and onpropertychange for better implementation.
- Added modified Attribute Name to the callback.
Thanks to @benvie for his feedback.
DEMO: http://jsfiddle.net/zFVyv/10/ (Tested in FF 12, Chrome 19 and IE 7.)
$(function() {
(function($) {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
function isDOMAttrModifiedSupported() {
var p = document.createElement('p');
var flag = false;
if (p.addEventListener) p.addEventListener('DOMAttrModified', function() {
flag = true
}, false);
else if (p.attachEvent) p.attachEvent('onDOMAttrModified', function() {
flag = true
});
else return false;
p.setAttribute('id', 'target');
return flag;
}
$.fn.attrchange = function(callback) {
if (MutationObserver) {
var options = {
subtree: false,
attributes: true
};
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(e) {
callback.call(e.target, e.attributeName);
});
});
return this.each(function() {
observer.observe(this, options);
});
} else if (isDOMAttrModifiedSupported()) {
return this.on('DOMAttrModified', function(e) {
callback.call(this, e.attrName);
});
} else if ('onpropertychange' in document.body) {
return this.on('propertychange', function(e) {
callback.call(this, window.event.propertyName);
});
}
}
})(jQuery);
$('.test').attrchange(function(attrName) {
alert('Attribute: ' + attrName + ' modified ');
}).css('height', 100);
});
Ref:
- Detect if DOMAttrModified supported
- DOMAttrModified for chrome
- Mutation Observer
- Why should we avoid using Mutation events?
- onPropertyChange IE
Mutation Observers is the proposed replacement for mutation events in DOM4. They are expected to be included in Firefox 14 and Chrome 18
Browser Support:
onpropertychange
- is supported in IE (tested in IE 7)
DOMAttrModified
- is supported in IE 9, FF and Opera
MutationObservers
- is very new and it worked fine in Chrome 18. Not sure how far it is supported and yet to be tested in Safari.
Thanks @benvie on adding info about WebkitMutationObserver

- 1
- 1

- 79,297
- 15
- 120
- 134
-
1Thanks! What is browser support like for `WebkitMutationObservers`? (How far back in chrome and safari does it go?) What about `onPropertyChange`? – user730569 Jun 12 '12 at 21:26
-
3MutationObservers are very new but are supported in very recent WebKit and Firefox. They are the future of DOM modification events though, and I'm happy to see them included in this answer. ++ this answer – Jun 12 '12 at 21:32
-
1Oh except it'd be better if it handled the unprefixed version as well (which Firefox 15 supports). `var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver`. – Jun 12 '12 at 21:33
-
@benvie Where could I find the specific browser versions that support them? – user730569 Jun 12 '12 at 21:37
-
Chrome 18, Firefox 13?, References: http://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/ https://bugzilla.mozilla.org/show_bug.cgi?id=749920 http://lists.webkit.org/pipermail/webkit-dev/2012-June/021039.html (it's worth noting that MutationObservers have 5-10x better performance than the Mutation Events they replace which is why vendors are so eager to get them out in the wild) – Jun 12 '12 at 21:38
-
@benvie Thanks for the pointers and the reference links. Updated the post. – Selvakumar Arumugam Jun 12 '12 at 21:49
-
I came up with a derivative of this that it's a bit more performant and includes property name as well (style changes are just named 'style' except with onpropertychange) https://gist.github.com/2920623 – Jun 12 '12 at 22:52
-
@benvie definitely a lot of improvements and also included some nice features.. let me try it out here and will update.. Thank you. – Selvakumar Arumugam Jun 12 '12 at 23:12
-
@user730569 It seems it is available since IE 5. >> http://www.blooberry.com/indexdot/html/tagpages/attributes/onpropertychange.htm < – Selvakumar Arumugam Jun 13 '12 at 17:58
-
@Vega: do these events get triggered when an element style is altered by non-programmatic means? e.g. a new stylesheet is loaded that affects rendering of a particular element – Oleg Jun 14 '12 at 05:55
-
2There's no need for the `attachEvent` branch in `isDOMAttrModifiedSupported`: DOM mutation event support coincides with `addEventListener` support in IE (both were introduced in IE 9). – Tim Down Jun 14 '12 at 08:32
-
@o.v I don't think so.. >> http://jsfiddle.net/skram/zFVyv/8/ << The style sheet is loaded later after the listeners. – Selvakumar Arumugam Jun 14 '12 at 14:04
-
@Vega: curious. I imagine that implies DOM mutation events don't necessarily reflect rendering mutations (probably for a good performance reason too) - worth mentioning in your answer imo – Oleg Jun 14 '12 at 22:29
-
This looks good, I've been using this plugin called CSS Tie, which still works well with the latest jQuery version (1.7). Check it out for inspiration... https://github.com/revsystems/jQuery-Tie – sg3s Jun 16 '12 at 18:00
-
@Vega: This is close to what I'm looking for, except that (for example) I also need to be notified when an element's width changes due to things like the window being resized (think about a block-level element whose width is set to '80%' and we're trying to monitor its width). Can you think of a way to extend this plugin's capabilities to do that? I realize that we could handle those changes separately, like [this](http://stackoverflow.com/a/6513415/718325), but I was hoping to get all of this functionality from one plugin. Thanks. – Jason Frank May 13 '14 at 18:47
EDIT2:
If you still want to use mutation observer
, use this library: mutation-summary
EDIT:
As I said in my answer below and thanks to Vega for his comment, using things such as object.watch
or mutation observers
are not recommended for using in large apps. this is actual quote from MDN:
Generally you should avoid using
watch()
andunwatch()
when possible. These two methods are implemented only in Gecko, and they're intended primarily for debugging use. In addition, using watchpoints has a serious negative impact on performance, which is especially true when used on global objects, such as window. You can usually use setters and getters or proxies instead. See Compatibility for details.Warning
So if cross-browser compatibility is in your check list, Again, I highly suggest overriding setter
s and getter
s of style
object.
use
object.watch
and have these in mind for a cross-browser solution:
- Javascript Object.Watch for all browsers?
- object.watch polyfill
- Watch for object properties changes in JavaScript
You may override getter
and setter
methods of element's style
object too.
There is a jQuery plugin available for this, jQuery watch
-
I think watch uses polling.. and OP is looking for _object changes without use of polling_ – Selvakumar Arumugam Jun 13 '12 at 09:02
-
1@Vega Well, I don't know about the source code of Gecko that much, but I think by 'polling' OP meant manual `setInterval`s, didn't? – Sepehr Jun 13 '12 at 11:15
I have found this little plugin that does exactly that and it can be changed to add any mutation you wish... Even scrollHeight change listener.
The plugin: http://www.jqui.net/jquery-projects/jquery-mutate-official/
here is the demo: http://www.jqui.net/demo/mutate/

- 17,336
- 23
- 95
- 144
-
This plugin uses an interesting approach, but it does use polling (see the `setTimeout(reset, mutate.speed);` line (you may need to un-minify it to make it readable). – Jason Frank May 13 '14 at 18:31
Even for all of the most modern browers there is no cross-browser way to achieve this. You would have to route all of your css style changes through a function which could trigger event listeners. This would be the cleanest method.

- 2,270
- 1
- 14
- 6
In an answer to a similar question, it was suggested that if you know that style-setting interactions would be performed via a standard interface (i.e. always using jQuery etc.) it was suggested that custom events be fired whenever the library method is called.
This would allow for a broader support matrix but would leave any property change ignored if performed without using the library method. It also appears that such an approach is not applicable to native setters as they cannot always be relied on.
You can use attrchange jQuery plugin. The main function of the plugin is to bind a listener function on attribute change of HTML elements.

- 26,379
- 14
- 93
- 105
-
4That is what Vega's answer says (http://stackoverflow.com/a/11004907/971299) in fact the plugin was written BECAUSE OF this question! – RyanfaeScotland Dec 08 '15 at 14:49