Besides the usual type, descendant, class and ID selectors, CSS offers several pseudo-class and pseudo-element selectors that allow us to target HTML elements based on their positions in the document –– some even target virtual elements and generate content from the CSS. In this article, we’ll take a look at 5 handy CSS selectors to keep in mind when styling your web pages and applications.
Contents
:first-child and :last-child
The :first-child
and :last-child
structural pseudo-classes let us select the first or last child of a parent element.
For example, if we only need to select the first list item of an unordered list, we can use the :first-child
pseudo-class:
li:first-child { border-top: none; font-weight: bold; }
Similar to :first-child
, the :last-child
pseudo-class selects an element that is the last child of its parent element.
li:last-child { border-bottom: none; }
:nth-child
:nth-child
is one of the most useful structural pseudo-classes available; it lets us select elements based on their positions within a parent element.
:nth-child
uses a function-like syntax that allows an argument to be passed in between parentheses –– inside the parentheses is where we declare how the elements will be selected.
One of the arguments that can be accepted is the keyword odd
or even
, which can be used to select every other child element. The following rule will only target the even-numbered list items.
li:nth-child(even) { color: white; background-color: black; }
Another argument we can use in between the parentheses is an integer. For example, this rule will only select the third list item inside the parent ul
.
li:nth-child(3) { background-color: tomato; }
What makes arguments really powerful is when using expressions to select a particular combination of child elements. Our basic expression syntax looks something like this:
:nth-child(an+b)
The values a and b are always represented by a number, and the n value does not change. The b value is an offset value that determines which element is selected first. The a value determines the cycle of elements to select after the first one has been selected. The n value doesn’t change — think of n as a counter that starts at zero and indicates the a value to the browser.
li:nth-child(2n+3)
In the expression above, the third list item will be the first one selected in our list (the b value) ignoring all sibling list items that precede it, then every 2nd list item (determined by the a value) until there are no more list items to select.
An expression like the one below will select the 5th list item first, then all list items before it (indicated by the -n value).
li:nth-child(-n+5)
Sometimes it may be beneficial—and practical—to use a class instead of an overly complex rule, as some can be difficult to maintain over time. For example, say you have a rule like the following:
div:nth-last-of-type(2n+10) { background: yellow; color: red; }
Think of the developer (or yourself) that has to manage this code a few weeks or months down the road. This is when we’re better off using a simple class such as:
.warning { background: yellow; color: red; }
:nth-of-type
:nth-of-type
selects an element based on its position within a parent’s list of children of the same type specified. This is a more flexible and useful selector if you want to be sure you’re selecting the same type of element no matter where it is inside the parent element or what other elements appear before it.
For example, if we only want to select the fourth image on the page, we need to first specify the img element, then :nth-of-type
followed by the argument.
img:nth-of-type(4) { border-color: red; }
:target
The :target
pseudo-class allows us to style elements based on the URI –– it selects the element that shares the same ID as the URI once it’s targeted by the browser. A link with a fragment identifier will link to an element within the document, known as the target element.
For example, say our HTML had the following elements:
<a href="#intro">Introduction</a> <a href="#conclusion">Conclusion</a> ... <div id="intro">...</div> <div id="conclusion">...</div>
Our CSS rule:
:target { border: 5px solid blue; }
The browser will target the div with the corresponding ID and apply the :target
selector styles once the link is clicked –– because when we click on a link that ends with a fragment identifier, that element we are pointing to becomes the target.
::before and ::after Pseudo-elements
Pseudo-elements let us target virtual elements that are not specified in the HTML. With the ::before
and ::after
pseudo-elements we can insert virtual elements before or after an element’s content that are visible to the user and are styleable in the CSS –– so we can actually add to our HTML from our CSS. This is called generated content.
::before
The ::before
pseudo-element will insert content before the selected element. In order for this to work properly we must use the content
property, otherwise we won’t be able to generate or insert any content. At the very least, it must contain empty quotes as its value.
.pdf::before { content: url(img/pdf.png); margin-right: 10px; }
In the example above, a PDF icon was generated before the link’s content.
::after
The ::after
pseudo-element works just like the ::before
pseudo-element except that it inserts content after the selected element’s content.
An important thing to keep in mind is that the generated content is not exactly inserted before and after the targeted element as expected. It’s actually inserted as child content in relation to the element.
blockquote::before { content: "\275D"; /* unicode icon for opening mark */ margin-right: 20px; } blockquote::after { content: "\275E"; /* unicode icon for closing mark */ margin-left: 20px; }
In this example, the opening quotation mark is actually inserted inside of the blockquote’s content box –– it’s inserted before the text and not before the actual blockquote
element. With the ::after
pseudo-element, the closing mark is inserted the same way, except that it’s appended to the content. I added a border around the blockquote
so we can clearly see how this works:
Support
The selectors we covered have excellent support in the major browsers. Selectors like :target
and :nth-child
, however, are not supported in IE8 and below. But IE8 does support the one-colon syntax for the :before
and :after
pseudo-elements.
These are just a few of the many pseudo-classes and pseudo-element selectors available to us. For a full summary of all selectors and their syntax, take a look at the Selectors Level 3 Module spec: http://www.w3.org/TR/css3-selectors/#selectors.