Take the 2-minute tour ×

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.

share|improve this question
I have an answer, but, are you targeting ancient browsers? or just major browsers? –  3p3r Jun 13 '12 at 8:34
@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, use getter and setter for maximum performance –  3p3r Jun 13 '12 at 16:07
show 1 more comment

7 Answers

up vote 39 down vote accepted

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:

  1. Fix for propertName in IE7 & IE8

Edit 1:

  1. Handle multiple elements
  2. Ordered the conditions as MutationObserver, DOMAttrModified and onpropertychange for better implementation.
  3. 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);

    $('.test').attrchange(function(attrName) {
        alert('Attribute: ' + attrName + ' modified ');
    }).css('height', 100);



  1. Detect if DOMAttrModified supported
  2. DOMAttrModified for chrome
  3. Mutation Observer
  4. Why should we avoid using Mutation events?
  5. 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

share|improve this answer
Thanks! 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
MutationObservers 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 –  benvie Jun 12 '12 at 21:32
Oh 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. –  benvie 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
There'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 8:32
show 11 more comments


If you still want to use mutation observer, use this library: mutation-summary


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() and unwatch() 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.


So if cross-browser compatibility is in your check list, Again, I highly suggest overriding setters and getters of style object.

use object.watch and have these in mind for a cross-browser solution:

You may override getter and setter methods of element's style object too.

There is a jQuery plugin available for this, jQuery watch

share|improve this answer
I think watch uses polling.. and OP is looking for object changes without use of polling –  Vega Jun 13 '12 at 9:02
@Vega Well, I don't know about the source code of Gecko that much, but I think by 'polling' OP meant manual setIntervals, didn't? –  3p3r Jun 13 '12 at 11:15
add comment

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/

share|improve this answer
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 May 13 at 18:31
add comment

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.

share|improve this answer
add comment

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.

share|improve this answer
add comment

You can use attrchange jQuery plugin. The main function of the plugin is to bind a listener function on attribute change of HTML elements.

share|improve this answer
add comment

Since you are using jQuery, you would be using jQuery .css function to update the style of an element.

In that case, you can simply override default jQuery .css function and trigger css change callback once after updating the default css. See below,

DEMO: http://jsfiddle.net/zFVyv/11/

(function($) {
    /* .css override*/
    var _cssfx = $.fn.css;  //Default function
    $.fn.css = function(a1, a2) {
        _cssfx.call(this, a1, a2);
        this.csscb.call(this, a1, a2); //trigger csschange callback

    $.fn.csschange = function(callback) {
        this.csscb = callback;
        return this;


$('.test').csschange(function(a1, a2){
      //your code for css change callback
    'height': 50,
    'width': 100

This solution is cross browser proof and will work in all browser that can run jQuery.

Note: This solution will only work for css style changes using .css jQuery method. This will not work when you update style attribute using native methods.

share|improve this answer
add comment

Your Answer


