dean.edwards.name/weblog/2005/08/cssquery2/

cssQuery Version 2

cssQuery is similar to Simon Willison’s getElementsBySelector. It is a bit more complicated but allows many more CSS selectors (e.g. attribute selectors). cssQuery also has a caching option which means that it gets faster the more you use it.

I held back on blogging about version 2.0 because some of the selectors were not working in Safari. Until I recently acquired an IBook, I was debugging cssQuery using BrowserCam. Obviously this is not the best way to debug complex JavaScript code! With access to a Macintosh computer I’ve now ironed out those last annoying Safari bugs. Browser coverage is now pretty comprehensive and the test page looks good in all the major browsers.

Available for download.

Comments (31)

Leave a comment

Excellent! Thanks Dean!

I’m a huge fan of your work and am very pleased to hear that you improved Safari support!

Thank you!

Great work!
I can see some uses for this!

On a related note, when is your IE7 going to work with PNGa set as background-image (or does it)?

  • Comment by: Alan H
  • Posted:

Thanks for this, Dean.

What I’d like to see, in addition to your cssQuery() method is a method that tests a specified element to see if it satisfies a given css selector. The behaviour.js library by Ben Nolan is an example of why this would be useful. That library uses Simon Willison’s getElementBySelector() function, but invokes it repeatedly on the same document, effectively traversing the document n times. In applications like this, I suspect it is more efficient to traverse the document once, testing each element in turn to see if it matches each selector of interest. I assume that this is the way browsers apply styles to a document…

Thanks Dean, now I can hack your cssQuery into the Behaviour library[1] to force better opera and safari support.

Implementing unobtrusive JS gets easier every day thanks to people like yourself! :)

[1]http://bennolan.com/behaviour/

  • Comment by: Andrew K
  • Posted:

Browsercam? I sure hope you didn’t pay for that, Dean…

  • Comment by: Dante
  • Posted:

The ability to select a parent element of a given node based on CSS attributes would be useful to me (and probably generally useful). In other words, CSS allows you to select down the DOM, whereas with CSSQuery, you could offer the ability to select up the DOM tree.

Browsercam? I sure hope you didn’t pay for that, Dean…

I have a free account provided by a satisified IE7 user. :-)

  • Comment by: -dean
  • Posted:

The Problem With Stacking Browser Event Handlers From JavaScript

I thought it was rather easy to do all this. I have a $ object that can get or test any element (cross browser or I’d use Element.prototype) based on id, tagName, attribute by String or RegExp. The code is only maybe 3k, and isn’t too slow – but I’m not doing anything fancy like caching.

It also provides a setAttributes() that you can pass pairs of strings to. As soon as I’ve set up dean’s starlight I’ll post the code up.

  • Comment by: Dan
  • Posted:

Great! I use CSSQuery a lot! Thanks! :)

  • Comment by: FataL
  • Posted:

I’ve been working with this and found one edge case that doesn’t work — attributes whose values contain brackets, such as “arrivaldate[]“. Trying to query these elements with cssQuery(“input[names='arrivaldate[]‘]”) doesn’t work.

Names like this are often used on PHP pages, to get multiple fields with the same name to form themselves into an array back on the server.

  • Comment by: Josh Santangelo
  • Posted:

(Of course the above should have been name= rather than names= — the bug remains, though. I’ve found ways to work around it, and the library itself has made my life much easier.)

  • Comment by: Josh Santangelo
  • Posted:

I think I found a problem with cssQuery() not returning a match with this selector:

div div ol li #beta { ... }

e.g.

<div>
<div>
<ol>
<li id="alpha">x</li>
<li id="beta">y</li>
</ol>
</div>
</div>
  • Comment by: Anthon Pang
  • Posted:

Anthon – that selector is not a match. You would need to use this instead:

div div ol li#beta { ... }

Note the removal of the space between li and #beta.

  • Comment by: -dean
  • Posted:

Thanks. My oopsie. :)

Please accept the following patches. The first is for IE4. The second rounds out the handling of supposed attribute naming conflicts.

--- /home/apang/download/ajax/cssQuery/src/cssQuery.js  2005-08-19 22:04:32.000000000 -0400
+++ cssQuery.js 2005-12-22 14:05:41.000000000 -0500
@@ -167,7 +167,7 @@
 // IE5/6 includes comments (LOL) in it's elements collections.
 // so we have to check for this. the test is tagName != "!". LOL (again).
 var thisElement = function($element) {
-       return ($element && $element.nodeType == 1 &&$element.tagName != "!") ? $element : null;
+       return ($element && (typeof $element.nodeType == "undefined" || $element.nodeType == 1) && $element.tagName != "!") ? $element : null;
 };

 // return the previous element to the supplied element

--- /home/apang/download/ajax/cssQuery/src/cssQuery-level2.js   2005-08-19 17:30:08.000000000 -0400
+++ cssQuery-level2.js  2005-12-22 14:03:41.000000000 -0500
@@ -95,9 +95,17 @@
                case "id":
                        return "e.id";
                case "class":
+               case "classname":
                        return "e.className";
                case "for":
+               case "htmlfor":
                        return "e.htmlFor";
+               case "http-equiv":
+               case "httpequiv":
+                       return "e.httpEquiv";
+               case "accept-charset":
+               case "acceptcharset":
+                       return "e.acceptCharset";
                case "href":
                        if (isMSIE) {
                                // IE always returns the full path not the fragment in the href attribute
  • Comment by: Anthon Pang
  • Posted:

I missed this additional change in cssQuery.js, and revised my patch for cssQuery-level2.js. (This just leaves an IE4 substitute for DOM traversal unimplemented, e.g., e.firstChild.)

@@ -228,7 +228,7 @@
 };

var getElementsByTagName = function($element, $tagName) {
-       return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);
+       return ($tagName == "*") ? ($element.all ? $element.all : $element.getElementsByTagName($tagName)) : ($element.all ? $element.all.tags($tagName) : $element.getElementsByTagName($tagName));
 };

 var compareTagName = function($element, $tagName, $namespace) {

--- /home/apang/download/ajax/cssQuery/src/cssQuery-level2.js   2005-08-19 17:30:08.000000000 -0400
+++ cssQuery-level2.js  2005-12-22 14:55:42.000000000 -0500
@@ -95,9 +95,17 @@
                case "id":
                        return "e.id";
                case "class":
-                       return "e.className";
+               case "classname":
+                       return "e.getAttribute('"+name+"')||e.className";
                case "for":
-                       return "e.htmlFor";
+               case "htmlfor":
+                       return "e.getAttribute('"+name+"')||e.htmlFor";
+               case "http-equiv":
+               case "httpequiv":
+                       return "e.getAttribute('"+$name+"')||e.httpEquiv";
+               case "accept-charset":
+               case "acceptcharset":
+                       return "e.getAttribute('"+$name+"')||e.acceptCharset";
                case "href":
                        if (isMSIE) {
                                // IE always returns the full path not the fragment in the href attribute
  • Comment by: Anthon Pang
  • Posted:

Uh, yeah…I missed the $ in $name in a couple of places. :|

  • Comment by: Anthon Pang
  • Posted:

Hi,

cssQuery now works with IE4.

Since my last comment, I’ve implemented the DOM traversal and moved most of the changes into cssQuery-standard.js. Some minor tweaks to the test page were also needed. You can find my diffs here:

http://www.advantax.org/public/cssQuery.diffs

Cheers,

– Anthon

If you’re still reading these comments, I think the problem in #12 can be fixed by changing the AttributeSelector regular expression to something like:

var AttributeSelector = {match:
/\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*('([^']|\\')*'|"([^"]|\\")*"|[^\]]*)\s*\]/
};
  • Comment by: Daniel James
  • Posted:

Hello there

I have a question to cssquery, i got the problem with the onload problem that it overwrite other onload functions how it is (was) in addEvent handler. Is there any solution for cssquery or am i just to stupid to see it :P.

Greets

  • Comment by: sUb*
  • Posted:

Ah sorry – it was my fault.. just had a error in reasoning.

  • Comment by: sUb*
  • Posted:

[...] cssQuery Version 2 [...]

[...] cssQuery Version 2 [...]

[...] cssQuery Version 2 [...]

[...] cssQuery, similar to get elementsbyselector: http://dean.edwards.name/weblog/2005/08/cssquery2/ [...]

[...] To start, I want to give a little bit of history regarding jQuery’s selector engine. When I first started working on its implementation it was mid-2005. It was mostly done as a personal challenge to myself – implementing a specification for kicks. You can see some of my early thoughts in a post that I wrote on Selectors in JavaScript. I completed my implementation on the same day as the first, other, JavaScript CSS selector engine: cssQuery. I then held of and merged it with some of my other efforts, which eventually resulted in jQuery. When I first implemented the engine, I went for full CSS 3 compliance (mashing in XPath-capable queries, as well). [...]

[...] várias outras funções mais poderosas que este ‘get’ simples mostrado. Pesquise, também, funções dos diversos frameworks existentes que facilitam o [...]

There’s a problem with cssquery when there are too many elements in the page. The script will take a long time to load, and in firefox, prompts a message asking if the user would want to continue to load the script (which is not very user-friendly). Is there a workaround for this?

  • Comment by: Kerwin
  • Posted:

[...] várias outras funções mais poderosas que este ‘get’ simples mostrado. Pesquise, também, funções dos diversos frameworks existentes que facilitam o [...]

[...] cssQuery Version 2 [...]

Leave A Comment

Line and paragraph breaks automatic, email address never displayed. Some HTML allowed.