1

With CSS selectors a selector string body > h1.span subscribes to a specific type of nodes in the tree. Does anyone know how this is done?

Selectors for transformations, how does the browser select the result set? And is there a trick to making it efficient?

I imagine there being some sort of hierarchical type-tree for the entire structure to which the nodes subscribe and which is what is used when doing the selector queries — but this is only a guess.

Does anyone know the real answer? Or even more interesting, what would be the best way to do dynamic lookups on a tree based on jQuery/CSS search queries?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Martin Kristiansen
  • 9,875
  • 10
  • 51
  • 83

2 Answers2

5

Most major browsers process a page and create a document hierarchy or document tree based on the elements in the page, according to the DOM. When applying CSS, they typically iterate the document tree, working on a per-element basis and performing right-to-left matching on the candidate selectors in a stylesheet for each element, then apply CSS rules based on these matches according to the CSSOM. This means for a selector like body > h1.span for example, a browser first checks each element to see if it's an h1 with a class of span, then checks if it's a direct descendant of body.

Depending on the implementation, there may be some optimizations to filter more likely non-matching cases. For instance, checking the namespace, tag name, ID, or class name, before attempting any other matching routines, as those are the most common ways to distinguish elements.

This per-element matching pattern allows a browser to effectively "subscribe" a selector to changes in the DOM, because all a browser would need to do (I imagine) is to look at changes in the DOM and apply rules and reflow the elements that were changed accordingly.

That is over-simplifying it, though. It also mainly refers to selector matching in a stylesheet. It doesn't describe every selector implementation, because the spec doesn't define implementations.

For example, browsers implement the Selectors API (document.querySelector() et al) differently, even though it uses CSS selectors for querying the DOM. In particular, there is no subscription model whatsoever; the node lists returned by Selectors API methods aren't dynamically updated. From §6.2 Finding Elements:

The NodeList object returned by the querySelectorAll() method MUST be static, not live ([DOM-LEVEL-3-CORE], section 1.1.1). Subsequent changes to the structure of the underlying document MUST NOT be reflected in the NodeList object. This means that the object will instead contain a list of matching Element nodes that were in the document at the time the list was created.

jQuery seems to perform right-to-left matching of selectors as well, according to some answers on this site, but I haven't found any supporting sources. It also has a number of optimizations such as body and ID selectors being read first, etc. And like the Selectors API, jQuery returns a static list of nodes that matched at the time its selector engine was invoked; it won't subscribe to changes in the DOM and update the node list accordingly (if you need to subscribe to DOM changes and delegate event handlers, you need to use .on() or a similar method with a selector).

It's worth noting that one major optimization that jQuery employs is to defer to the Selectors API for matching selectors first. This means it uses the browser's native implementation rather than JavaScript. If the selector is valid CSS and supported, document.querySelectorAll() returns a node list. If it errors out otherwise, jQuery falls back to its own selector engine, Sizzle, for querying the DOM.

Again, it's not strictly identical to browsers' implementation of CSS selectors, in particular because jQuery selectors and CSS selectors are not the same thing, even though one is an adaptation of the other.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
1

As you may be aware CSS rules are evaluated right-to-left, so in your example the entire DOM is scanned for class .span first and then filtered by tag h1.

Barry Kaye
  • 7,682
  • 6
  • 42
  • 64
  • No, that's not how right-to-left matching works. See [this answer](http://stackoverflow.com/a/5813672/106224) for a counter-example (which calls it pre-filtering and not RTL matching). – BoltClock Sep 25 '12 at 09:16