This article is a proper guide on CSS selectors. If CSS is the decoration of your house, the CSS selectors are the tools used to decorate your house.
What are CSS selectors?
You have met selectors already. A CSS selector is the first part of a CSS Rule. It is a pattern of elements and other terms that tell the browser which HTML elements should be selected to have the CSS property values inside the rule applied to them. The element or elements which are selected by the selector are referred to as the subject of the selector.
Selector lists
If you have more than one thing which uses the same CSS then the individual selectors can be combined into a selector list so that the rule is applied to all of the individual selectors. For example, if I have the same CSS for an h1
and also a class of h2
, I could write this as two separate rules.
h1 {
color: blue;
}
h2 {
color: blue;
}
I could also combine these into a selector list, by adding a comma between them.
h1,
h2 {
color: blue;
}
White space is valid before or after the comma. You may also find the selectors more readable if each is on a new line.
h1,
h2 {
color: blue;
}
Types of selectors
There are a few different groupings of selectors, and knowing which type of selector you might need will help you to find the right tool for the job.
1. Type, class, and ID selectors
This group includes selectors that target an HTML element such as an <h1>
.
h1 {
}
It also includes selectors which target a class:
.box {
}
or, an ID:
#unique {
}
2. Attribute selectors
This group of selectors gives you different ways to select elements based on the presence of a certain attribute on an element:
a[title] {
}
I really like attribute selectors. They’re just so flexible when you need to match elements containing attributes with specific values.
3. Pseudo-classes and pseudo-elements
This group of selectors includes pseudo-classes, which style certain states of an element. The :hover
pseudo-class for example selects an element only when it is being hovered over by the mouse pointer:
a:hover {
}
It also includes pseudo-elements, which select a certain part of an element rather than the element itself. For example, ::first-line
always selects the first line of text inside an element (a <p>
in the below case), acting as if a <span>
was wrapped around the first formatted line and then selected.
p::first-line {
}
If you’ve worked on styling forms, then you’ve undoubtedly encountered these types of pseudo-classes before:
:enabled
:disabled
:checked
We can use pseudo-classes to match whether input values are valid or not directly with CSS, as well as check if any elements are required before the form can be submitted.
:valid
:invalid
:required
:optional
(i.e., not required)
Next, we have two pseudo-classes that can match if a form element (that supports min and max attributes) is in range or not.
:in-range
:out-of-range
- You can learn more about pseudo selectors from here.
4. Combinators
Let’s start in familiar territory. Combinator selectors are used to selecting child elements, as well as siblings, and have been around for quite a while now.
General child selector (space), e.g.,
A B
Direct child selector, e.g.,
A > B
Adjacent sibling selector, e.g.,
A + B
General sibling selector, e.g.,
A ~ B
The adjacent selector A + B
should be familiar to you. It selects the element B
, which immediately follows A
. But what about the general sibling selector A ~ B
? This selects all sibling elements B
that follows A
.
Here’s an example of them both in action:
5. Structural selectors
This type of selector is different from the ones shown so far, as some of them allow you to pass in a parameter to modify how the selector works.
For example, :nth-child()
has an argument that is used to match a specific child element relative to it. The value can be an index (beginning at 1) or an expression.
So, if we had a list of items the following selector would match the third item:
ul:nth-child(3)
It can be a simple expression instead that makes the pseudo-class even more powerful.
Valid expressions are:
ul:nth-child(2)
: matches the second child elementul:nth-child(4n)
: matches every fourth child element (4, 8, 12, …)ul:nth-child(2n +
1) : matches every second child element offset by one (1, 3, 5, …)ul:nth-child(3n — 1)
: matches every third child element offset by a negative one (2, 5, 8, …)ul:nth-child(odd)
: matches odd-numbered elements (1, 3, 5, …)ul:nth-child(even)
: matches even-numbered elements (2, 4, 6, …)
The expression variable n always starts as zero, so to work out exactly what elements will be matched, start with n as zero, then n as 1, and so on to compile a list of elements.
The next set of selectors is specialized structural selectors as they match specific child elements only. You can’t pass expressions to them to modify their behavior.
:first-child
:last-child
:only-child
:first-of-type
:last-of-type