Using JavaScript's CSS3 Selectors

By Rob Gravelle

6/23/13

The HTML5 selectors API has given Web developers unprecedented access to document elements. Developed by the W3C, the Selectors API provides a way of easily accessing elements in the DOM using a standardized syntax. All modern browsers - even IE8 - support them. In this article, we'll learn how to use JavaScript to reference page elements using the new CSS selectors.

New Attribute Selectors

CSS3 has added three new substring selectors to the existing CSS2 set, namely: the caret character (^) "starts with" substring selector, the the dollar symbol ($) "ends with" substring selector, and the asterisk (*) operator "contains" substring selector. These may be utilized to target a rule and apply CSS styling to an element based on part of an attribute's value. For example, we can reference all external links in our document (that start with "http://") by using the caret character (^) "starts with" attribute substring selector in order to add an identifying icon:

a[href^="http://"] { 
   background:url(images/external_link.png) 100% 50% no-repeat;
}

The Selectors JavaScript API

The Selectors API is not technically part of the W3C HTML5 spec, but is its own separate, small specification. It adds the querySelector() and querySelectorAll() methods to the Document, Element, and DocumentFragment objects.

These add to existing DOM methods, including:

  • getElementById(): From DOM Level 2 Core, it is a member of the document element.
  • getElementsByClassName(): After long non-standardized browser support, getElementsByClassName() was finally standardized in HTML5. It is supported by the document and elements.
  • getElementsByTagName(): Also part of the DOM Level 2 Core, getElementsByTagName() is applicable to the document and element objects.

We can also make use of various properties to traverse the DOM. These include:

  • childNodes: A property of the document and node objects, it references the node's contained elements.
  • nextSibling: Property of a node, it references the element directly following it at the same level under a common parent element.
  • parentElement: Also a node property, it references the node's containing element.

Using the querySelector() Method

This method is a member of the document as well as page elements. It returns the first descendent element that matches the supplied selector string. Interestingly, we can use it in place of the document.getElementById('elementID') method by prepending the pound (#) character in front of the ID string: document.querySelector('#content'). Here's some code that retrieves a <DIV> element by ID and then applies the querySelector() method to it in order to return the first exterior link, using the CSS# selector that we created in the first example:

//replaces getElementById('linksDiv')
var linksDiv = querySelector('#linksDiv'); 

//get the first external link in the DIV
var firstExternalLink = linksDiv.querySelector('a[href^="http://"]');

Just don't forget the #, because omitting it won't throw an error, so it can be difficult to debug.

The best thing about the querySelector() method is that it accepts any selector type, including attribute, structural, dynamic, UI, and even selector groups. This makes locating a specific element far simpler, and quicker, as we don't have to traverse the DOM and loop over numerous elements and their properties. Moreover, one can only assume that the browser's native DOM engine runs the query much more quickly.

Using the querySelectorAll() Method

Just like querySelector(), it takes a CSS selector string as an argument. Only, instead of returning a single element, querySelectorAll() returns a NodeList of matching elements. Here are some examples:

document.querySelectorAll('.mygroup') //returns all elements with class="mygroup"
document.querySelectorAll('option[selected="selected"]') //returns the default selected option within each SELECT menu
document.querySelectorAll('#mytable tr>td:nth-of-type(1)') //returns the first cell within each table row of "mytable"

We can then iterate through this array using JavaScript, and manipulate these objects. The following function identifies all checkboxes that are selected within the 'ProfileForm' form and returns their values in an array:

function getHobbies(aForm) {
   var myHobbies      = [], 
       checkedHobbies = aForm.querySelectorAll('input[name="hobbies"]:checked');
   for (var i=0; i<checkedHobbies.length; i++){
     myHobbies.push(checkedHobbies[i].value);
   }
   return myHobbies;
}

alert('My hobbies are ' + getHobbies(document.querySelector('#ProfileForm')));

Testing For Browser Support

All modern browsers, including IE8 and up support querySelector() and querySelectorAll(). However, the capabilities of both methods may be limited by what CSS selectors the browser supports. This is especially an issue with Internet Explorer. IE8 supports CSS2.1 selectors, though not CSS3 selectors, while IE9 supports many CSS3 selectors, but not some of the UI related pseudo-classes, such as ":required" and ":visited".

Nonetheless, it can't hurt to test for browser support before using either of the new methods. Here are a couple of approaches, the first being more rudimentary, the second, more strict:

  function supportsQuerySelectors() {
    return ((document['querySelector'] && document['querySelectorAll']) != null);  //convert to boolean
  }

 

  function supportsQuerySelectors() {
    return (  typeof document['querySelector']    == 'function' 
           && typeof document['querySelectorAll'] == 'function');
  }

Conclusion

CSS has come along way since its humble beginnings, as has JavaScript's access to document elements. The querySelector() and querySelectorAll() methods are a welcome addition the the Web developer's arsenal of DOM tools. They'll make your code simpler and faster in one fell swoop.


If you enjoyed this article, please contribute to Rob's rock star aspirations by purchasing one of Rob's cover or original songs from iTunes.com for only 0.99 cents each.

Rob Gravelle resides in Ottawa, Canada, and is the founder of GravelleWebDesign.com. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses. EmailRob to receive a free estimate on your software project.

In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His former band, Ivory Knight, was rated as one Canada's top hard rock and metal groups by Brave Words magazine (issue #92).

Rob uses and recommends MochaHost, which provides Web Hosting at $3.10 per month, 2 LifeTime Free Domains, and 6 Months Free!



Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •