The 36 CSS Selectors to Master

CSS Selectors
By Aditya Samanta Updated

From classic web designs to modern flat designs, CSS still remains the beauty manager of the web and continues to evolve. Long gone are the days when we were limited to element, class and id selectors. Look under the hood and you will find that CSS now has a whole new arsenal of selectors.

The advanced CSS selectors are very powerful. You can combine with traditional CSS selectors to do some nifty things. Today, we look at all the advanced CSS selectors in CSS 3.

Specificity & Performance

Using a complex selector will increase the specificity. That means you will need to add more specific rules if you want to override the previous one. This can quickly bloat your CSS and make maintenance a  nightmare.

Another problem with complex CSS selectors is that they are more time expensive. They force the browser to do more work. Try avoiding complex selectors unless absolutely necessary. Performance should always be one of your goals.

Many of the new CSS 3 selectors are DOM based. DOM will change over time. If you are not careful, you may end up spending hours debugging your CSS.

Direct Child Selector

The direct child selector is represented by a greater than sign (>). This selects all direct child elements of a parent element. It uses the following syntax

a > b { ... }

This selector will find all elements matched by selector b which are direct children of the target element matched by selector a. Here is an example where we select all header elements which are direct children of a section element.

HTML

<section>
    <header>Selected</header>
    <article>
        <header>Not Selected</header>
    </article>
    <article>
        <header>Not Selected</header>
    </article>
</section>

CSS

/* Match all header elements which are direct children of a section element */
section > header { ... }

Sibling Selectors

In CSS level 3, two different sibling CSS selectors are available – the adjacent sibling selector and the general sibling selector.

The adjacent sibling selector

The selector is represented by a plus sign (+) between two CSS selectors. It uses the following syntax:

a + b { ... }

The target elements of both selector  a and b must share a common parent. Also, the target element of selector  b must immediately follow the target element of selector  a.

HTML

<div>
    <h1></h1>
    <p>I am immediate sibling, select me</p>
</div>

CSS

/* Target all p elements which immediately follow h1 element */
h1 + p { ... }

General sibling selector

The general sibling selector is represented by a tilde sign (~) between two CSS selectors. Like the name suggests, this is a more general version of sibling selector. It uses the following syntax:

a ~ b { ... }

This will select the target element matched by selector b that share the same parent as the element represented by selector a. The element matched by selector b must follow the element represented by selector a though not immediately.

HTML

<div>
    <h1></h1>
    <h2></h2>
    <p>I am sibling, select me</p>
</div>

CSS

/* Target all p elements which share the same parent as h1 and come after h1 */
h1 ~ p { ... }

CSS Attribute Selectors

With CSS attribute selectors, you can target elements with specific attributes. You have lots of options when targeting elements with this selector.

The attribute present selector

[x]

The most basic form of CSS attribute selector. You can use it to match any element that has the x attribute. It does not matter what the value is. The value may not even exist, it will still match. In the following example, we match all img elements that has an alt attribute.

img[alt] { ... }

The attribute equals selector

[x=y]

Match all elements whose x attribute value is exactly equal to y. In the example below, we are finding an element based on id attribute without using the id selector (high specificity).

/* Find element with id = the-id */
[id=the-id] { ... }

The attribute whitespace separated selector

[x~=y]

Match all elements with the x attribute whose value is a list of one or more values separated using whitespace and one of the those values exactly match y. Here is an example showing how to find elements based on class with this alternate syntax.

/* Both match any element with class foo */
.foo { ... }
[class~=foo] { ... }

The attribute hyphen separated selector

[x|=y]

Match all elements with the x attribute where the value is hyphen separated rather than space separated. The attribute value must be equal to the y or must begin with y. This selector is primarily intended to match language subcode in the HTML tag.

The language attribute is most commonly applied on the root HTML element. The following will select an HTML element whose language attribute begins with en like en-US.

[lang|=en] { ... }

The attribute begins with selector

[x^=y]

This is used to find elements based on an attributes starting value. The selector will match all elements with x attribute whose value begins with y. Here is an example showing how to style HTTP and HTTPS external links.

a[href^="http://"] { color: blue; }
a[href^="https://"] { color: green; }

The attribute ends with selector

[x$=y]

This is opposite to the attribute begins with the selector. This is used when finding elements based on an attributes end value. The selector will match all elements with x attribute whose value ends with y. The following selector will match all images whose src attribute ends with .png

img[src$=".png"] { ... }

The attribute contains selector

[x*=y]

This is a wildcard selector. You can use it to find elements based on a partial attribute value. The selector will match all elements with x attribute whose value contains y. In the following example, we find all elements whose class contains alert somewhere.

HTML

<div class="alert"></div>
<div class="alert-info"></div>
<div class="alert-success"></div>

CSS

[class*=alert] { ... }

Pseudo-class selectors

These are CSS selectors which do not appear in the markup. They can’t be expressed using normal selectors. All pseudo-class selectors begin with a single colon (:) sign followed by the name of the pseudo-class. The most common pseudo-class selector is :hover.

Dynamic pseudo-classes

These pseudo-class selectors are dynamic in nature. They don’t appear in the source or the document tree. When a user is interacting the document an element will gain or lose a dynamic pseudo-class.

Link pseudo-classes

The link pseudo-classes are used to differentiate between the links which the user has visited and the links which the user is yet to visit.

There are two CSS selectors here: the :link pseudo-class represents links that the user is yet to visit and the :visited pseudo-class represents the visited links.

a:link { ... }
a:visited { ... }

User action pseudo-classes – :hover, :active, :focus

Three pseudo-class selectors are available for times when a user is interacting with an element.

The :hover pseudo-class selector is applied to an element when the user moves the cursor over it.

The :active pseudo-class selector is applied to an element when it is activated. For example, when a user presses the primary mouse button on an element, it will remain active till the user releases the mouse button.

The :focus pseudo-class selector is applied to an element when it gains focus. This happens when using the keyboard tab key to navigate elements.

a:hover { ... }
a:active { ... }
a:focus { ... }

Target pseudo-class

Some URI’s contain a fragment identifier or anchor identifier. You see this as a number sign (#) followed by a string. The fragment identifier is actually a link to a resource, in this case – an element inside the document called the target element.

If there is an element in the document, whose id exactly matches the fragment identifier then target attribute is applied to the element. If the fragment identifier changes or does not match any element then it is deactivated. The following URI has a fragment identifier of section-logo.

www.example.com/docs.html#section-logo

HTML

<!-- Link to fragment -->
<a href="#logo"></a>

<!-- section with fragment identifier -->
<section id="logo">
 ...
</section>

CSS

section:target { ... }

Language pseudo-class

:lang(x) { ... }

For any document that specifies the human language, you can use language pseudo-class to target elements based on the language. This selector will come handy when coding a multi-language site. The following example matches an HTML document that is in the German language.

html:lang(de) { ... }

The Language pseudo-class CSS selector is different from the attribute hyphen separated CSS selector. The :lang(x) selector is aware of the document language and will match any element that is using the specified language. The attribute hyphen separated selector [x|=y] only scans attribute values and tries to match them. If the attribute is not present then it does not work.

For example, in the following example, both body and H1 match :lang(de) but only body matches [lang|=”de”]

HTML

<body lang=de>
 <h1>Advanced CSS Selectors - Language</h1>
</body>

CSS

/* works */
body:lang(de) { ... }
/* works */
body[lang|=de] { ... }
/* works */
h1:lang(de) { ... }
/* does not work */
h1[lang|=de] { ... }

The UI element states pseudo-classes

This pseudo-class selectors are applicable to user interface elements. Currently, there are four UI element states pseudo-classes. The first two work on UI elements that can exist in an enabled and a disabled state. The last two work on radio buttons and checkboxes.

The :enabled pseudo-class selector applies to user interface elements that are in an enabled state. The :disabled pseudo-classes  selector is the opposite and applies to user interface elements that are in a disabled state. Any element that has an enabled state also has a corresponding disabled state.

:enabled { ... }
:disabled { ... }

A user can toggle radio buttons and checkboxes. The :checked CSS selector selects radio buttons and checkboxes which are currently checked or toggled on. This selector won’t be applied if the user toggles the state to unchecked.

:checked { ... }

Sometimes a checkbox or a radio button exists in an indeterminate state where it is neither checked nor unchecked. Such elements can be targeted using the  :indeterminate pseudo-class. If you create radio buttons without names, they should be in indetermintate state whether checked or not.

:indeterminate { ... }

Structural pseudo-classes

The Structural pseudo-classes rely on information present in the document tree which can’t be expressed using normal CSS selectors. They rely on the position of an element in the document tree.

How nth-* CSS selectors work

The nth-* selectors are some of the most advanced CSS selectors available. They rely on (an+b) equation where the value of a and b must be integers and n represents natural numbers. Here are some things you should remember while using this advanced CSS selectors:

  • The nth-* selectors are index based.
  • This first child of any element has an index equal to 1.
  •  For an element to be selected, the final value of the equation must be greater than 0.
  • If you provide a single integer value, then it is considered as the value of a.
  • If n is unspecified then it defaults to 1.
  • When n is specified it starts from 0.
  • If n is negative and a is unspecified then a defaults to 1.
  • The value of both a and n can never be negative at the same time (This just means that an is positive).
  • When unspecified b defaults to 0.
  • Both a and b accept negative values.

Let’s start with something simple. What if we want to select every li element that is the 3rd child of its parent element. We can use the following CSS selector.

/* select every 3rd child li element */
li:nth-child(3) { ... }

If you specify a single negative value, then the selector won’t work, as index begins at 1. The following selector does not work as it is trying to access an element at index -3.

/* invalid - does not work */
li:nth-child(-3) { ... }

Let’s modify our CSS selector to select all child li elements whose index is a multiple of 3. All we have to do is set the value of a to 3 and add n (Remember n is a natural number). This works like (3*0), (3*1), (3*2), (3*3) and so on.

/* Select all child li elements whose index is a multiple of 3 */
li:nth-child(3n) { ... }

Now, it’s time to add b to our equation. When b is a positive integer and an is also a positive integer, b acts as an offset. In our equation, if we set the value of b to 1, then it will select every 3rd li element starting at offset 1 i.e. 1, 4, 7 and so on.

/* Select every 3rd child li element starting at offset 1 */
li:nth-child(3n+1) { ... }

If the value of b is negative and the value of an is positive, then b acts as a negative offset. The following will select every 3rd element starting from -1 i.e. -1, 2, 5, 8 and so on.

/* Select every 3rd child li element starting at offset -1 */
li:nth-child(3n-1) { ... }

The above CSS selector can also be written using a positive value of b.

/* Select every 3rd child li element starting at offset 2 */
li:nth-child(3n+2) { ... }

If the value of an is negative and the value of b is positive, then b acts as an upper limit for search. All child elements which are at a higher index than b will be ignored. This can be used to limit the search to first b elements. The following CSS selector will select first 3 child elements.

/* Select first 3 child li elements */
li:nth-child(-n+3) { ... }

If you want to limit the search even more then you can add a to the equation. By specifying  the value of a as -3 and b as 9,  we can limit the search to find the multiples of 3 up to 9.

/* Select all child li elements which are multiples of 3 up to 9 */
li:nth-child(-3n+9) { ... }

You can select all odd child elements using the odd keyword.

/* Select all odd child li elements */
li:nth-child(odd) { ... }

This, of course, can also be written as the following

/* Select all odd child li elements */
li:nth-child(2n+1) { ... }

As you might expect, you can also select all even child elements using the even keyword

/* Select all even child li elements */
li:nth-child(even) { ... }

Again, you can choose to rewrite the above CSS selector with the following one

/* Select all even child li elements */
li:nth-child(2n) { ... }

Now that you know how the nth-* based advanced CSS selectors work let’s look at the available options.

:nth-child()

This pseudo-class selector works using child element index inside a parent. When specified a value using the (an+b) equation, selection will be made based on child index. All the following selectors are same

/* All are same */
li:nth-child(1n+0) { ... }
li:nth-child(n+0) { ... }
li:nth-child(n) { ... }
li

Be careful when using this selector when other types of elements are present. For example, in the following example, a br element is located at index 3 so you won’t be able to select the 3rd child p element with :n-child(3) selector.

HTML

<div>
    <p>Lorem ipsum dolor sit amet.</p>
    <p>Lorem ipsum dolor sit amet.</p>
    <br>
    <p>Lorem ipsum dolor sit amet.</p>
</div>

CSS

/* does not work */
p:nth-child(3) { ... }

:nth-last-child()

Working on the same principles as :nth-child pseudo-class selector, this pseudo-class selector works backwards and starts finding child elements from the end. Everything else is same. For example, the following CSS selector can be used to find the last 3 child li elements.

/* Find all last 3 child li elements */
li:nth-last-child(-n+3) { ... }

:first-child

The :first-child pseudo-class selector represents the first child of a parent element. It is a short-hand way of using :nth-child(1) CSS selector. The following CSS selector will select any h1 element which is the first child of their parent element.

/* Select any h1 element which is the first child of its parent element */
h1:first-child { ... }

:last-child

The :last-child pseudo-class selector represents the last child of a parent element. It is a short-hand way of using :nth-last-child(1) CSS selector. The following CSS selector will select any h1 element which is the last child of their parent element.

/* Select any h1 element which is the last child of its parent element */
h1:last-child { ... }

:nth-of-type()

The :nth-of-type pseudo-class selector is used to find sibling elements which are of same type. This is extremely handy in cases where different type of elements are present inside a parent.

While using the :nth-child selector a while ago, we were unable to find the 3rd child p element when a br tag was present at the 3rd index. We can use :nth-of-type pseudo-class selector instead.

HTML

<div>
    <p>Lorem ipsum dolor sit amet.</p>
    <p>Lorem ipsum dolor sit amet.</p>
    <br>
    <p>Lorem ipsum dolor sit amet.</p>
</div>

CSS

/* Find 3rd p sibling of all p elements  */
p:nth-of-type(3) { ... }

/* Does not work */
p:nth-child(3) { ... }

:nth-last-of-type

The :nth-last-of-type pseudo-class selector is just like :nth-of-type pseudo-class selector but starts finding sibling element from the end. Other than working backwards, everything else remains same. In the following example, we find last two even p sibling elements.

/* Find the last two sibling p elements with even index */
p:nth-last-of-type(-2n+4) { ... }

:first-of-type

The :first-of-type pseudo-class selector is a short-hand way of using the :nth-of-type(1) pseudo-class selector. This is used to find the first sibling element of its type inside a parent element.

/* Find the first h1 element inside any parent */
h1:first-of-type { ... }

:last-of-type

The :last-of-type pseudo-class selector is a short-hand way of using the :nth-last-of-type(1) pseudo-class selector. This is used to find the last sibling element of its type inside a parent element.

/* Find the last h1 element inside any parent */
h1:last-of-type { ... }

:only-child

The :only-child pseudo-class selector is used to find an element which is the only child element of its parent. All the following CSS selectors are same. Observe how the :only-child selector has the lowest specificity.

/* All are same */
:only-child { .. }
:first-child:last-child { ... }
:nth-child(1):nth-last-child(1) { ... }

:only-of-type

The :only-of-type pseudo-class selector is another short-hand selector. It is used to find an element which is the only of its type inside a parent element. Look at the selectors below, they are all valid and do the same task but :only-of-type pseudo-class selector has the lowest specificity.

/* All are same */
:only-of-type { ... }
:first-of-type:last-of-type { ... }
:nth-of-type(1):nth-last-of-type(1) { ... }

:root pseudo-class

The :root CSS selector represents the root document element. In a HTML 4 or HTML 5 document this will be your HTML element.

:root { ... }

:empty

The :empty pseudo-class targets any element which lacks child elements. Child elements include other nodes and text including whitespace. Note that comments and processing instructions are ignored.

HTML

<!-- empty -->
<p></p>
<!-- not empty -->
<p> </p>
<!-- not empty -->
<p>Foo</p>
<!-- empty -->
<p><!-- bar --></p>
<!-- not empty -->
<p> <!-- bar --> </p>

CSS

/* Select all empty p nodes */
p:empty { ... }

The negation pseudo-class :not

:not(x)

The negation pseudo-class denoted by :not(x) takes a selector as an argument and filters out the elements which contain the specified selector. CSS 3 does not support nesting of negations i.e. :not(:not(…)) is invalid. The following will select all p elements with foo class that does not have the bar class.

HTML

<p class="foo">Foo Only</p>
<p class="foo bar">Foo + Bar</p>

CSS

p.foo:not(.bar) { ... }

Pseudo-elements

The pseudo-elements offer mechanisms to access certain parts of the document which can’t be accessed normally. The pseudo-elements also offer ways to insert dynamic information into the document that does not exist in the source document.

To use a pseudo-element, write two colons (::) immediately followed by the name of the pseudo-element. For compatibility, pseudo-elements introduced in CSS level 1 and CSS level 2 (:first-line, :first-letter, :before and :after) can be accessed using a single colon (:).

The backward compatibility is not available for pseudo-elements introduced in CSS level 3 and above. The ::selection CSS pseudo-element is one of such elements. Initially, it was supposed to be a part of CSS level 3 but now it is a part of CSS level 4 draft.

The ::first-line pseudo-element

The ::first-line pseudo-element identifies the first line of text within a node. This only works when attached to a block like container such as block, inline-block, list-item, table-caption, or table-cell. In the example below, we are targeting the first line of all p elements that have the highlight class.

/* Match first line of all p elements with highlight class */
p.highlight::first-line { ... }

The ::first-letter pseudo-element

The ::first-letter pseudo-element selects the first letter of an element if no other element precedes it. The ::first-letter pseudo-element is most often used to create typographical effects like initial caps and drop caps. Just like ::first-line, this too only works with block like containers.

/* Select first letter of all elements with dropcap class added */
.dropcap::first-letter { ... }

The ::before and ::after pseudo-elements

The ::before and ::after pseudo-elements allow dynamic content to be inserted within an element. They are most commonly used to add cosmetic stuff. Both ::before and ::after pseudo-elements are inline by default.

Also, note that ::before and ::after pseudo-elements are only supported inside elements which support child elements. Elements like img, textarea do not support child elements. This means that they can’t have ::before and ::after pseudo-elements.

The following example shows how to use ::before and ::after pseudo-elements in CSS

/* CSS 2 */
.foo:before { ... }
/* CSS 3 */
.foo::before { ... }
/* CSS 2 */
.foo:after { ... }
/* CSS 3 */
.foo::after { ... }

Conclusion

Wow! That’s a whole lot of CSS selectors. The best way to learn is to try them out. You can turn it up a notch and group all sorts of selectors together to do some crazy things.

Some of the selectors mentioned here are really basic CSS selectors while some other are truly advanced CSS selectors. Compatibility is also great on all modern browsers.

Just because they are available doesn’t mean that you have you to use them. Use what you find is best for your requirement and skills.

Resources & Links

  • Selectors Level 3 – https://www.w3.org/TR/css3-selectors/
  • Taming Advanced CSS Selectors – https://www.smashingmagazine.com/2009/08/taming-advanced-css-selectors/
  • The 30 CSS Selectors You Must Memorize – http://code.tutsplus.com/tutorials/the-30-css-selectors-you-must-memorize–net-16048