CSS3 Selectors

css3 selectors and javascriptCSS3 has added the ability to target almost any element on the page with a wide range of selectors.

We’ve been keeping up with the Cascading Style Sheet evolution.  We’ve been matching elements by type, class, and/or id.  Then we got familiar with the pseudo-elements, pseudo-classes and combinators.

CSS3 is an extension of CSS2.1 that adds powerful new functionality and has been divided up into several modules.  Each module has a standalone specification for a subsection of CSS, like selectors, text, or backgrounds.  The list of changes is quite exhaustive and can be researched at http://www.w3.org/Style/CSS/current-work.

  1. The original CSS specification had about 6 selectors.
  2. CSS2 introduced attribute selectors & CSS2.1 expanded the range with 12 more selectors.
  3. CSS3 introduces over a dozen new selectors.
  4. CSS3 did not add any new pseudo-elements, but refined these special selectors to now use a double colon as the proper syntax (::) to differentiate between the two types of selectors.
  5. CSS3 provides three new attribute selectors (ie., href or title) and one new combinator – that is, a selector that joins other selectors together, such as the child combinator (>) from CSS2.  The Selectors Level 3 Module has widespread and stable implementation across most browsers.  When I say most browsers, it usually means IE8+, and most all other browsers, who have been keeping up with the evolution.

We can get into the Document Object Model (DOM) to manipulate our elements.

A Quick Overview of useful, supported changes from CSS3:

CSS3 contains a lot of new properties that allow you to create visual fx, such as rounded corners, drop shadows, semitransparent backgrounds, gradients, and images for borders. Most of these changes are in the Background and Borders module; others in the Colors and Images modules.

You can manipulate a box’s position and shape in two- or three-dimensional space, such as rotating, scaling, or skewing it.  These effects are called transforms, and are covered in the 2D and 3D Transforms modules.

The Fonts module introduced the @font-face rule that allows you to link to a font file on your server and use it to display the text on your page, instead of being limited to the fonts on your user’s machine.

CSS3 introduces over a dozen new selectors. They are included in the Selector module.  The pseudo-class and attribute selectors allow you to target specific pieces of your HTML without needing to add IDs or classes, streamlining your code.

The Transitions and Animation module allows you to ease changes from one style on an element to another, such as gradually and smoothly changing the color of a button when you hover over it.  You can make complicated style changes and movements.

Multi-column Layout is a module that makes multi-column layouts easier to create.  It deals with flowing the text of a single block into multiple columns, similar to a newspaper layout.  The Flexible Box Layout module deals with making blocks align horizontally or vertically with each other and making them more flexible to the available space than floats or positioning can be.

Before moving on, let’s recap how a selector might be utilized.  Here is a short contact list example:

<li><a href=”” lang=”en-GB” rel=”friend met”>Peter</a></li>
<li><a href=”” lang=”es-ES” rel=”friend”>Pedro</a></li>
<li><a href=”” lang=”es-MX” rel=”contact”>Pancho</a></li>

All of these elements have a rel attribute which we can use to target all of the elements. The advantages of having more methods for traversing the document mean fewer styling hooks are required.  Here is another example:

<li class=”1first 2pretty”>3<span>L</span>orem ipsum</li>
<li>Lorem ipsum</li>
<li class=”pretty”>Lorem ipsum</li>
<li class=”4last”>Lorem ipsum</li>

This markup contains class names to describe each element’s position in the document tree:   first (1) and last (4) show that the li elements are the first and last children on the ul element, and pretty (2) is used to the odd-numbered li elements.  An extra span (3) is included around the first letter of the li element.  Use this example to add styles to alternating elements, set different values on the first and last elements, or add special formatting to the first letter of a text node.

Here is the list of selectors from CSS2:

a[rel] {color:red;}Simple Attribute Selector – all elements will have this rule applied to it. a[rel=’friend’] {color: red;}Exact Attribute Value Selector – will only target elements with the value of friend, so it would be the second element.
a[rel~=’friend’] {color:red;}Partial Attribute Value Selector – selects both of the elements that contain the value of friend.  It looks for the value of friend as part of a space-separated list, and applies to the first and second elements.
a[lang|=’es’] {color: red;}Language Attribute Selector applies rules to elements based on their lang attribute.  This would target both the second and third elements in our example because we targeted just es, and did not specify ES or MX.

CSS3 Introduces New Selectors 

The new Selectors already have widespread support, including IE8+.  CSS3’s new methods allow you to achieve the same visual results without muddying the markup with unnecessary classes and non-semantic elements.

a[attr^=val] – matches any element a whose attribute attr starts with the value val.  The val matches the beginning of the attribute value.  a[title^=’image’] {} –  rule will be applied to the a element in the first paragraph since the title attribute string begins with the word image.

a[attr$=val] – matches any element a whose attribute attr ends in val.  The val matches the end of the attribute.

a[attr*=val] – matches any element a whose attribute attr matches val anywhere within the attribute.  The string val is matched anywhere in the attribute value.  It is similar to a[attr~=val] above, except the val can be part of a word.  For example, .fakelink[title~=info] {} would match any element with the class fakelink that has a title attribute containing the string info, such as “Click here for more information.”

Selectors can be broadly separated into two categories, but they both sit outside the DOM

What’s the difference between a pseudo-class(:) and a pseudo-element(::)?

Remember this:  pseudo-classes select HTML elements that could have classes added to them, while pseudo-elements select things that aren’t HTML elements at all.

The four pseudo-elements in CSS are ::first-line, ::first-letter, ::before, and ::after.  Fragments of other HTML elements, not individual elements themselves, and not part of the DOM.  A double colon (::) is the correct syntax, but the single colon is better supported.  IE6, IE7 and IE8 only understand the single-colon notation.  All other browsers support both.

Pseudo-classes act directly on elements defined in the document tree (ie., p elements and href attributes); this category contains class, type, and attribute selectors, or DOM selectors.  E:first-child {} allows you to make a selection based on information that exists but isn’t provided as an attribute of the element – the exact purpose of a pseudo-class.

The pseudo-classes that we are familiar with for some of our user interaction are classes, namely :link, :visited, :hover, :active, and :focus, aka dynamic or interactive pseudo-classes.  The pseudo-class uses a single (:) colon.

Generated Content – The ::before and ::after pseudo-elements don’t refer to content that exists in the markup, but rather to a location where you can insert additional content, generated right there in your CSS.  While this generated content doesn’t become part of the DOM, it can be styled.  Notice the attr() allows you to access any attributes of the selected element.  Here is an example:

a[href^=http]:after {
content: “(” attr(href) “)”;
The a[href^=http] means “any a element whose href attribute begins with http, or in other words, external links.  You can use this to display the link’s target.  I tried it and it worked.  Another example might be like this:

a[href$=pdf] {
background: transparent url(pdficon.gif) 0 50% no-repeat;
padding-left:  20px;
a[href$=pdf]:after {
content:  “(PDF)”;
This style will add a PDF icon and the text”(PDF)” after links to PDF’s.  Remember that the [attr$=val] selector matches the end of an attribute .pdf., and of course, you need the image that will be displayed for you at 50% transparency.

Things to remember now….. 

1.  The :visited pseudo-class may pose a security risk, and may not be fully supported in the future.  Malicious sites can apply a style to a visited link, then use JavaScript to check the styles of links to popular sites.  This allows the attacker to glimpse the user’s browsing history without their permission.  As a result, several browsers have begun limiting the styles that can be applied with :visited and some others (notably Safari 5) have disabled it entirely. The spec explicitly condones these changes, saying:

“UAs [User Agents] may therefore treat all links as unvisited links,or implement other measures to preserve the user’s privacy while rendering visited and unvisited links differently.”

2.  For better accessibility, add :focus wherever you include :hover, as not all visitors will use a mouse to navigate your site.

3.  :hover can apply to any element on the page – not just links and form controls.

4.  :focus and :active are relevant to links, form controls, and any element with a tabindex attribute.

These are the most common pseudo-classes, but there are many others.  The following pseudo-classes match elements based on attributes, user interaction, and form control state.  They have been part of the spec-planned evolution and are currently being supported in most cases:

:enabled – a user interface element that’s enabled.
:disabled – a user interface element that’s disabled.
:checked – radio button or checkboxes that are selected or ticked.
:indeterminate – form elements neither checked or unchecked.  Not supported yet.
:target – this selector singles out the element that is the target of the currently active intrapage anchor.  You know you can have links to anchors within a page by using the # character with the id of the target.  This changes the URL in the address bar to thispage.html#content – and the :target selector now matches the #content element, as if you had included the selector #content.
:default – applies to one or more UI elements that are the default among a set of similar elements.
:valid – applies to elements that are valid, based on the type or pattern attributes.
:invalid – applies to empty required elements, and elements failing to match the requirement defined by the type or pattern attributes.
:in-range – applies to elements with range limitations, where the value is within those limitations.  Applies, for example, to number and range input types with min and max attributes.
: out-of-range – the opposite of :in-range: elements whose value is outside the limitations of their range.
:required – applies to form controls that have the required attribute set.
: optional – applies to all form controls that do not have the required attribute.
:read-only – applies to elements whose contents are unable to be altered by the user.  This is usually most elements other than form fields.
:read-write – applies to elements whose contents are user-alterable, such as text input fields.

Browsers that support form control attributes like required and pattern also support the associated :valid and :invalid pseudo-classes.

IE6 fails to understand :hover on elements other than links, and neither IE6 nor IE7 understand :focus.  IE8 and earlier lack support for :checked, :enabled, :disabled and :target.  However, IE9 does support these selectors.
JavaScript libraries such as jQuery can help in targeting these pseudo-classes in nonsupporting browsers.
   See my article about the JavaScript shim.

Relational Selectors

Relational selectors target elements based on their relationship to another element within the markup.  All are supported in IE7+, Firefox, Opera and WebKit:

Descendant (E F)

The descendant selector targets any element F that is a descendant (child, grandchild, great grandchild, and so on) of an element E.  For example, ol li targets li elements that are inside ordered lists.  This would include li elements in a ul that’s nested in an ol – which might not be what you want.

Child (E > F)

This selector matches any element F that is a direct child of element E – any further nested elements will be ignored.  The ol > li would only target li elements directly inside the ol, and would omit those nested inside a ul.

Adjacent Sibling (E + F)

This will match any element F that shares the same parent as E, and comes directly after E in the markup.  For example, li + li will target all li elements except the first li in a given container.

General Sibling (E + F)

This one is tricky. It will match any element F that shares the same parent as any E and comes after it in the markup. So, h1-h2 will match any h2 that follows an h1, as long as they both share the same direct parent – that is, as long as the h2 is not nested in any other element.

Here is an example:

<h1>Main Title</h1>
<h2>This subtitle is matched</h2>
<p>blah, blah, blah…</p>
<h2>This is not matched by h1-h2, but is by header h2</h2>
<p>blah, blah, blah…</p>

The selector string h1-h2 will match the first h2, because they’re both children, or direct descendants, of the header. The second h2 doesn’t match, since its parent is article, not header. It would, however, match header h2. Similarly, h2-p only matches the last paragraph, since the first paragraph precedes the h2 with which it shares the parent article.

There aren’t any parent or ancestor selectors.  If the browser had to go backwards up the DOM tree, or recurse into sets of nested elements before deciding whether or not to apply a style, rendering would be exponentially slower and more demanding in terms of processing.

Another example would be if you wanted a three column layout for the site, and you want the three columns divs to be floated left (normal).  To avoid this style being applied to any other divs nested inside the main div, we use the child selector.  This is a basic form structure that you will be using:

#main > div {
float: left;
overflow: hidden;

Structural Pseudo-classes

The nth-* Pseudo-Class – Four of the new pseudo-classes are based on a count value used to find an element’s position in the document tree, and you use the syntax nth-*.  The asterisk is in place of a number of different values, each of which we will cover.  It is quite straightforward.  By default, n represents a number that begins at 0 and increments by 1 (1, 2, 3, etc.).  Another integer can be passed into it as a multiplier.  For example, 2n is every multiple of 2 (2, 4, 5, etc.), 3n is every multiple of 3 (3, 6, 9, etc.), and so on:

E:nth-*(n) {}   **Default value n, so all elements are selected**
E:nth-*(2n) {}
E:nth-*(3n) {}
The first example uses the default value n, so all elements of type E would be selected – the same thing as using a simple element selector.  The next example selects every other E element.

You may also use the mathematical operators for plus (+) and minus (-).  So 2n+1 would be every multiple of two plus one (1, 3, 5, etc.), 3n-1 would be every multiple of three minus one (2, 5, 8, etc.):

E:nth-*(n+1) {}   **selects every element except for the first instance, so 2, 3, 4, 5, etc.**
E:nth-*(2n+1) {}
E:nth-*(3n-1) {}

So now that we know how to target elements based on their attributes and states, we can also use CSS3 to target elements based simply on their location in the markup.  These selectors are grouped under the heading structural pseudo-classes.  

These might seem complicated, but they will make sense when you go to use them.  These selectors are supported in IE9, as well as current and older versions of all the other browsers – but not in IE8 and below.

You write the position number of the element you want to select inside the parenthesis (the argument), such as li:nth-child(5).  This selector would match the fifth li element in a list.  It gets powerful when you use a formula as its argument, allowing you to create more complex alternating patterns or even select specific blocks of sequential children at at time.  n is a counter starting at zero, and b is an offset value that you pick.  Example:

Since n starts at zero and then increases by one each cycle, this selector would match:
(3 x 0) + 1 = 1 = 1st list item
(3 x 1) + 1 = 4 = 4th list item
(3 x 2) + 1 = 7 = 7th list item, etc….

You could add classes to the first, fourth and seventh item, but this is easier to write, and easier to maintain.  If you ever wanted to add another list item, you would have to re-class all the list items from that point forward because their position number has changed.  Using the :nth-child() pseudo-class, that keeps track of the position number for you is more efficient and mistake-proof.

Don’t let the math scare you off from using the :nth-child().  Play around with it and see how it affects your styles.  You can check out http://www.leaverou.me/demos/nth.html to try this tool to play around with the :nth-child(), :nth-last-child(), :nth-of-type(), and :nth-last-of-type().

Here is another example, which will produce an alternating color variation within a list:
li:nth-child(even) {
background-color: hsla(210, 70%,82%,.5);
This will create a blue background to every other list item.  Cool!
I quickly found out that to write about all things new in CSS3 would require writing a book.  I’ve just touched upon a few things that you will need to get started with CSS3.

Here are some more things to chew on for a while:

:root – the root element, which is always the html element.
E F:nth child(n) – the element F that is the nth child of its parent E.
E F:nth-last-child(n)  – the element F that is the nth child of its parent E, counting backwards from the last one.  li:nth-last-child(1) would match the last item in any list – this is the same as li:last-child (see below).
E:nth-of-type(n) – the element that is the nth element of its type in a given parent element.
E:nth-last-of-type(n) – like nth-of-type(n), except counting backwards from the last element in a parent.
E:first-child – the element E that is the first child E of its parent.  It is the same as :nth-child.
E:last-child – the element E that is the last child E of its parent, same as :nth-last-child(1).
E:first-of-type – same as :nth-of-type(1).
E:last-of-type – same as :nth-last-of-type(1).
E: only-child – an element that’s the only child of its parent.
E:only-of-type – an element that’s the only one of its type inside its parent element.
E:empty – an element that has no children; this includes text nodes, so <p>hello</p> will not be matched.
E:lang(en) – an element in the language denoted by the two-letter abbreviation (en).
E:not(exception) – this is a particularly useful one:  it will select elements that don’t match the selector in the parentheses.

Selectors with the :not pseudo-class match everything to the left of the colon, and then exclude from that matched group the elements that also match what’s to the right of the colon.  The left-hand side matching goes first.  For example, p:not(.copyright) will match all the paragraphs in a document first, and then exclude all the paragraphs from the set that also have the class of copyright.  You can string several :not pseudo-classes together. h2:not(header > h2):not(.logo) will match all h2s on a page except those that are in a header and those that have a class of logo.

I referenced three books and the W3C website.  I hope if you are reading this, that you learn something.  I know I did, but there is more…..

Gastston, Peter. *The Books of CSS3*. San Francisco: no starch press 2011.
Goldstein, Alex; Lazaris, Louis; Weyl, Estelle. *HTML5 & CSS3 for the Real World*. Australia: Sitepoint.
Gillenwater, Zoe Mickley. *Stunning CSS3*. Berkeley: New Riders.


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s