How To Use CSS Combinators and Simple Pseudo Class Selectors

Last week we began looking at some of the selectors we have available for hooking css styles into our html. We briefly touched on some simple selectors and mainly focused on attribute selectors.

This week I want to continue and talk specifically about combinators before starting to cover pseudo class selectors.

Note: As a reminder the numbers in parenthesis after the combinator or pseudo-class are the version of css they were introduced in.

Combination lock

Combinators

Combinators, as the name suggests, are ways to combine several different selectors into new and more specific selectors.

There are 4 types of combinators targeting parent/child and sibling relationships between elements.

Descendant combinator E F (1) — matches an element F that’s a descendant of an element E. Note that descendant combinators target all descendants and not just direct children.

1
2
3
4
5
6
7
8
9
10
<ul>
  <li>List Item 1</li>
  <li>List Item 2
    <ol>
      <li>List Item 2-1</li>
      <li>List Item 2-2</li>
    </ol>
  </li>
  <li>List Item 3</li>
</ul>
1
ul li {background: red;}

All 5 list items will be styled with a red background as each is a descendent (either child or grandchild) of the unordered list.

Child combinator E > F (2) — matches an element F that’s a child of an element E. The difference here is that F must be a direct child of E.

1
2
3
4
5
6
7
8
9
10
<ul>
  <li>List Item 1</li>
  <li>List Item 2
    <ol>
      <li>List Item 2-1</li>
      <li>List Item 2-2</li>
    </ol>
  </li>
  <li>List Item 3</li>
</ul>
1
ul>li {background: red;}

Only list items 1, 2 and 3 above will be styled with a red background. Both are children of the ul, while list items 2-1, and 2-2 are grandchildren.

Adjacent sibling combinator E + F (2) — matches an element F immediately preceded by an element E. Note the word adjacent. Only the first element F after E will be targeted.

1
2
3
4
<h1>Heading</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
1
h1+p {font-size: 1.5em;}

Only paragraph 1 will be styled with the increased font-size as it’s the only paragraph adjacent to the h1.

General sibling combinator E ~ F (3) — matches an element F preceded by an element E. Unlike the above this will match any sibling and not just the first.

1
2
3
4
<h1>Heading</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
1
h1~p {font-size: 1.5em;}

Here all three paragraphs will have the increased font-size as all are preceded by the h1. It isn’t necessary for the elements to be adjacent in the general sibling combinator.

Beyond Simple Selectors

Note that you aren’t limited to only using simple elemental selectors in combinators. Any selector, including attribute selectors can sit on either side of the combinator.

1
2
3
4
ul a[title]
li#first>a[rel="external"]
h1+p.intro
h2.myclass~p[class="intro"]

All of the above are valid combinators.

Illustration of a classroom

Pseudo-Class Selectors

There are a variety of pseudo-class selectors, one group of which, I’m sure you use often. Others you may have seen and even used before and some will probably be new to you.

The W3C divides pseudo-classes into the following groups:

  • dynamic pseudo-classes
  • target pseudo-class
  • language pseudo-class
  • UI element pseudo-class
  • negation pseudo-class
  • structural pseudo-classes

We’ll cover the first 5 above today and then pick up next week with structural pseudo-classes and another group of selectors, pseudo elements.

Dynamic Pseudo-Classes

This is the group I’m sure you’re familiar with. It consists of the link and user action pseudo-classes and should look instantly familiar.

link pseudo-classes (1)

E:link — matches an element E that’s the source anchor of a hyperlink of which the target is not yet visited.

E:visited — matches an element E that’s the source anchor of a hyperlink of which the target has already been visited.

user action pseudo-classes (1) and (2)

These match an element E during certain user actions

E:active — When the link is active (in the process of being clicked).

E:hover — When the visitor hovers over the link.

E:focus — When the link has active focus.

I’ll assume you know all of the above well enough that little explanation is necessary.

One tip when using :link, :visited, :hover, and :active on a single element is that they need to come in that order. Remember the expression LoVeHAte.

Target pseudo-class (3)

If you’ve ever created a named anchor by adding a # to a url then you’ve created a target pseudo-class in your html.

E:target — matches an element E that’s the target (named anchor) of the referring url.

1
2
<a href="domain.com/this-page.html#a-specific-page-location"></a>
<span id="a-specific-page-location"></span>
1
span:target {background: yellow;}

The above would place a yellow background behind the span.

These are good to use to help quickly orient people who’ve clicked to a specific part of a page from another page or from somewhere else on the same page.

Lang pseudo-class (2)

E:lang(fr) — matches an element of type E in the language specified (here “fr” or French)

1
2
3
<body lang=fr>
  <p>Je suis fran&ccedil;ais.</p>
</body>
1
p:lang(fr) {color: red;}

I’m not sure how often you use multiple languages on a single page, but if you do here’s a way to target specific text in a different language.

CSS selectors

UI element states pseudo-classes (3)

A common trick to improve form usability is adding constraints like enabling and disabling form items based on what the visitor has already filled out.

Note that by default html elements are neither enabled nor disabled. A scripting language like Javascript is typically used to enable or disable the elements, however you could manually set html attributes on the inputs.

E:enabled — matches a user interface element E which is enabled.

E:disabled — matches a user interface element E which is disabled.

E:checked — matches a user interface element E which is checked (radio-button or checkbox).

1
2
3
4
5
6
7
<form>
  Preferred Contact:
    <input type="radio" id="prefer" value="email" checked="checked" /> Email
    <input type="radio" id="prefer" value="phone" /> Phone
  Email: <input type="text" id="email" enabled="enabled" />
  Phone: <input type="text" id="phone" disabled="disabled" />
</form>
1
2
3
:enabled {color: green;}
:disabled {color: red;}
:checked {background: yellow;}

Here red and green are used to let visitors quickly determine which form elements are currently available. Checked items are given a yellow background so they stand out as having been checked.

Presumably we’d use Javascript to change the enabled and disabled attributes based on which method is chosen as preferred.

Negation pseudo-class (3)

The negation pseudo-class does what you might expect. Adding it selects everything other than the selector being negated.

E:not(S) — matches an E element that does not match simple selector S.

1
2
3
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
1
div:not(.two) {color: orange;}

The above styles all the text in the first and third divs to be orange, since these two divs do not have a class of two assigned. The negation selector looks simple enough, but it can get quite complex in a hurry.

You’ll likely be able to find other ways to target the elements you want rather than use the negation selector, however one negation might be able to replace quite a few other selectors and may be more appropriate to use at times.

Browser Support

Support for combinators is good once you get past IE6. It’s not quite as good for pseudo-classes (outside of the dynamic pseudo-classes, which have good support) where we’re generally looking at IE9 and up for support.

You can check the links below to see the support for any of the specific selectors.

DNA strands in rainbow colored canisters

Summary

As was the case with attribute selectors I’m guessing you’ve used some of these combinators and pseudo-classes before. I’m also guessing most of what’s here you don’t use. That’s certainly true for me.

Outside of the generic descendant combinator and the dynamic pseudo-classes, I can’t say many of these ever find their way into my code. Some like :lang probably won’t come up that often, but hopefully you can see the benefit of the UI element states, the negation selector, and the other combinators.

Next week I’ll wrap up this quick walk through of selectors. We’ll look at the last of the pseudo-classes, the structural pseudo-classes and then look at pseudo-elements. Both will apply to some very practical ways we’re likely to want to style our pages.

Download a free sample from my book, Design Fundamentals.

2 comments

  1. Very nice and helpful article Steven. I really like to use pseudo classes and don’t wanna miss them any more. If you use them (for example :before & :after)you can reduce the HTML code. That’s the way to more semantic and faster coder and …

Leave a Reply

Your email address will not be published.

css.php