93

Is there a way to detect if the "display" css property of an element is changed (to whether none or block or inline-block...)? if not, any plugin? Thanks

HP.
  • 19,226
  • 53
  • 154
  • 253

5 Answers5

94

Note

Mutation events have been deprecated since this post was written, and may not be supported by all browsers. Instead, use a mutation observer.

Yes you can. DOM L2 Events module defines mutation events; one of them - DOMAttrModified is the one you need. Granted, these are not widely implemented, but are supported in at least Gecko and Opera browsers.

Try something along these lines:

document.documentElement.addEventListener('DOMAttrModified', function(e){
  if (e.attrName === 'style') {
    console.log('prevValue: ' + e.prevValue, 'newValue: ' + e.newValue);
  }
}, false);

document.documentElement.style.display = 'block';

You can also try utilizing IE's "propertychange" event as a replacement to DOMAttrModified. It should allow to detect style changes reliably.

jpaugh
  • 6,634
  • 4
  • 38
  • 90
kangax
  • 38,898
  • 13
  • 99
  • 135
  • Thanks. Will it support Firefox ? – HP. Sep 09 '09 at 05:00
  • Yes, IIRC, FF2 and up to a current one. – kangax Sep 09 '09 at 05:37
  • This won't work if the effective CSS display property for an element is changed indirectly; for example, by changing the CSS class of the element. – Tim Down Sep 23 '09 at 13:03
  • @Tim Down: In that case the event is still fired. You have to watch for modification of `@class` and can use getComputedStyle afterwards. – Boldewyn Nov 11 '11 at 09:45
  • 7
    @Boldewyn: True, but changing the `class` attribute (or any other attribute if attribute selectors are present in the CSS) of an ancestor of the element could also change the element, so you'd have to handle all `DOMAttrModified` events on the document root element to be sure of catching everything. – Tim Down Nov 12 '11 at 15:37
  • 12
    That event is deprecated in w3c. It must be another way. – ccsakuweb Jul 02 '12 at 06:55
  • 8
    The mutation events have been marked as deprecated in the DOM Events specification, as the API's design is flawed. Mutation Observers are the proposed replacement. Here's the link [https://developer.mozilla.org/en-US/docs/DOM/Mutation_events] – Anmol Saraf Oct 26 '12 at 19:00
  • A great replacement for `DOM*` is [`animationStart` and some CSS](http://stackoverflow.com/a/13835369/237285). – Andres Riofrio Dec 12 '12 at 08:08
  • 1
    Anmol - the MDN link for Mutation events should be: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events – groovecoder Feb 27 '14 at 13:49
  • @kangax. Can you help me on this link. https://stackoverflow.com/questions/45429746/dont-lose-previous-position-of-rzslider-after-select-the-date-in-angular-js?noredirect=1#comment77835931_45429746 – Varun Sharma Aug 02 '17 at 09:56
  • @kangax. I've updated your answer to reflect the current state of affairs. Although valid at the time, I wouldn't recommend using mutation events nowadays. – jpaugh Jul 02 '18 at 19:15
19

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

Code sample:

$("#myDiv").attrchange({
    trackValues: true, // set to true so that the event object is updated with old & new values
    callback: function(evnt) {
        if(evnt.attributeName == "display") { // which attribute you want to watch for changes
            if(evnt.newValue.search(/inline/i) == -1) {

                // your code to execute goes here...
            }
        }
    }
});
Muhammad Reda
  • 26,379
  • 14
  • 93
  • 105
  • Note that for some plugins that modify CSS evnt.attributeName is 'style' not 'display'. – jerrygarciuh Apr 17 '15 at 20:35
  • Works well but this is faster than using regex search and you don't need the first if(evnt.attributeName...): if (evnt.newValue.indexOf('display: inline-block') > -1) { ...; return;} – Dan Randolph Oct 15 '15 at 16:24
4

You can use jQuery's css function to test the CSS properties, eg. if ($('node').css('display') == 'block').

Colin is right, that there is no explicit event that gets fired when a specific CSS property gets changed. But you may be able to flip it around, and trigger an event that sets the display, and whatever else.

Also consider using adding CSS classes to get the behavior you want. Often you can add a class to a containing element, and use CSS to affect all elements. I often slap a class onto the body element to indicate that an AJAX response is pending. Then I can use CSS selectors to get the display I want.

Not sure if this is what you're looking for.

ndp
  • 21,546
  • 5
  • 36
  • 52
3

For properties for which css transition will affect, can use transitionend event, example for z-index:

$(".observed-element").on("webkitTransitionEnd transitionend", function(e) {
  console.log("end", e);
  alert("z-index changed");
});

$(".changeButton").on("click", function() {
  console.log("click");
  document.querySelector(".observed-element").style.zIndex = (Math.random() * 1000) | 0;
});
.observed-element {
  transition: z-index 1ms;
  -webkit-transition: z-index 1ms;
}
div {
  width: 100px;
  height: 100px;
  border: 1px solid;
  position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="changeButton">change z-index</button>
<div class="observed-element"></div>
IgorL
  • 1,169
  • 10
  • 19
-20

You can't. CSS does not support "events". Dare I ask what you need it for? Check out this post here on SO. I can't think of a reason why you would want to hook up an event to a style change. I'm assuming here that the style change is triggered somwhere else by a piece of javascript. Why not add extra logic there?

Community
  • 1
  • 1
Colin
  • 10,630
  • 28
  • 36
  • 1
    I have several events that can trigger a box to appear or not. And I have another element that kinda depends on the appearance of that box to do things. Now, I don't want to repeat code and hook up to all other events making appearance to the box although that is one way to do it. Just redundance! – HP. Sep 09 '09 at 02:31
  • It is redundant, maybe using a rule based system would work? ie, some JSON like structure that defines what should happen to some control when another control changes? this way you would only need to create 1 function tht uses the rule object and perhaps the current control(id) as parameter? – Colin Sep 09 '09 at 02:43
  • 3
    Why is this downvoted? Defining class for the parent of both elements and changing style on it is the only right solution for this. – Ilia G Dec 06 '11 at 14:16
  • 12
    Downvoted for "I can't think of a reason why you would want to hook up an event to a style change" - if you can't think of a reason it doesn't mean there is no possible reason, and for "Why not add extra logic there?" - because you can't always modify the scripts. – Andrei Cojea Jan 28 '15 at 14:52
  • To provide an example, I want to change the fill property of an svg path when the colour property of the parent element changes. – Andrei Cojea Jan 28 '15 at 14:54