
How to detect DOM changes in CSS - OmarIsmail
http://blog.streak.com/2012/11/how-to-detect-dom-changes-in-css.html
======
geuis
Its a very clever technique, but unfortunately its very fragile and may not
really be needed.

By fragile, I mean that you must construct your css to be _very_ specific in
order for this technique to trigger properly. Any non-expected changes to the
DOM are rather difficult to trap for. This somewhat limits its applicability.

DOM Mutation Events were, indeed, very performance intensive. They've been
deprecated for a while now and are gradually being removed from browsers.
However, there is a replacement in the works and WebKit/Firefox browsers
already support it.

Enter Mutation Observers. [https://hacks.mozilla.org/2012/05/dom-
mutationobserver-react...](https://hacks.mozilla.org/2012/05/dom-
mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/)

With Observers, you can target a specific parent node and be informed of any
changes to its children. Its highly performant and eventually should be
available in all platforms (IE taking the longest to adopt it).

I do see room here for an interesting compromise though. It seems we might be
able to combine both techniques to have a universal wrapper for detecting DOM
changes across any browser in a relatively efficient manner.

While IE9+ may not have all of the cutting edge features to be found in
Chrome, IE9+ have exceedingly fast javascript engines and graphics
acceleration. Its entirely reasonable to expect a DOM Mutation Observer shim
for IE9+ to behave rather well.

~~~
OmarIsmail
Thanks for pointing out the new MutationObserver API! I actually wasn't aware
of that, so for exhaustive comparison I'd have to do more research into it.
Reading up on the API there are a few issues that I see though:

1) You still have the same DOM structure brittleness. For detecting insertions
you have to bind to a an ancestor node and monitor each change to see if the
new nodes are of the type you're interested in - which is essentially through
selectors/traversal.

2) with the CSS technique you can structure the selectors/animations to only
trigger when the specific nodes come into existence. It's true that you have a
callback on every animation fired, but that's a simple switch case that
executes super fast. With MutationObserver you have to do a lot more
processing on each callback, including interacting with the DOM to figure out
which nodes were added/changed/deleted - and accessing the DOM is quite slow.
I think you'll have to be really careful with these MutationObservers or you
can run into situations where you do have a big performance hit.

~~~
geuis
Interesting discussion Omar. I think combining the API with the css technique
could lead to some interesting uses.

------
csuwldcat
Hey whatdayaknow, the method I created! Here's a follow-up I published a while
back that provides an generic listener method using the technique:
[http://www.backalleycoder.com/2012/08/06/css-selector-
listen...](http://www.backalleycoder.com/2012/08/06/css-selector-listeners/)

------
pavel_lishin
Damn, this is almost what I was looking for earlier.

I was trying to figure out how to tell when an iframe's document size changed
(because, for instance, a $(node).show() was called), in order to adjust a
custom html-and-js powered scrollbar.

~~~
pedalpete
I tried doing that in 2001, it was aweful. Have you got it solved yet? I was
thinking about this because the other day I was trying to intercept child
scrolling events on mobile OS.

------
mnicole
Very cool. Maybe this is a silly question, but any reason you're using 2n and
2n+1 instead of just "even" and "odd"? Is it just to avoid targeting the
first-of-type?

------
colinsidoti
I'm not very familiar with Chrome development, but it seems like you have
pretty strong capabilities. Why couldn't bind to the click event on the
Compose button?

~~~
OmarIsmail
Answered here: <http://news.ycombinator.com/item?id=4791596>

Summary is that there are a lot more ways than clicking on the compose button
to bring up a compose window.

~~~
colinsidoti
Hmm, still seems kinda messy to rely on CSS.

Next thought, maybe you can override Google's open method with something like
this: <http://jsfiddle.net/Z3Ysq/>

They may have been able to prevent this with a closure, but I think you could
workaround everything. Watch out for scope issues, but I think there's a way
to make this completely generalizable.

That being said, I agree that at some point, it might get too messy figuring
this all out that your existing solution is best. Kudos for the clever
concept.

~~~
OmarIsmail
You look at Gmail's JS and tell me which function is the "open compose" :)

Someone who can do that would get hired pretty quickly!

------
csuwldcat
Just one little citation of the original article that demonstrated this hack
would be nice. The guy references David Walsh's blog (a friend of mine), who
even in the article cites and attributes the method, yet doesn't include it in
here? Just a tad lame, that's all:
[http://www.backalleycoder.com/2012/04/25/i-want-a-
damnodeins...](http://www.backalleycoder.com/2012/04/25/i-want-a-
damnodeinserted/)

------
mnutt
It's an interesting hack, but it seems like the DOM changes that they're
trying to detect all result from some user event. (clicking "reply" or
something) Wouldn't it be easier to just listen for that user event?

~~~
OmarIsmail
Not necessarily true. It's not through reply, but instead compose. And
theoretically you could bind to all the trigger events, but you may miss some,
and there's a lot of bindings...

You can click on the big compose button in the top right. You can use one of
the two keyboard shortcuts, you click click on an email address in an email,
you can click on the email icon in the little contact card, etc.

Binding to all of those events (such as the contact card) is about as
difficult, if not more so, than binding to the creation of new compose windows
themselves.

------
charlesboudin
try this <https://addons.mozilla.org/en-US/firefox/addon/firediff/>

------
fraserharris
This is an awesome hack Omar, thanks for sharing.

