22. CSS Pseudo-classes

What you will learn

  • What a pseudo-class is
  • Interaction states: hover, focus, active
  • Position selectors: first-child, last-child, nth-child
  • Form states: checked, disabled, required, invalid
  • Useful helpers: :not() and :is()

What is a pseudo-class?

A pseudo-class selects an element in a particular state or position. It is written with a single colon after a selector, for example button:hover.

Syntax

selector:pseudo-class {
  property: value;
}

Interaction states

Pseudo-class Matches when
:hover The pointer is over the element
:focus The element has keyboard focus (or is clicked into)
:focus-visible Focus should be shown, typically for keyboard users
:active The element is being pressed

Example

<style>
  button {
    padding: 10px 20px;
    color: white;
    background-color: #0d6efd;
    border: 0;
    border-radius: 6px;
    cursor: pointer;
  }
  button:hover { background-color: #082b59; }
  button:active { transform: scale(0.97); }
  button:focus-visible { outline: 3px solid #f59f00; outline-offset: 3px; }
  input:focus { background-color: #fffbe6; }
</style>

<button type="button">Hover, press, or Tab to me</button>
<p><input type="text" placeholder="Click into me"></p>

Output (the state changes work in the live editor)

Position in a family

Pseudo-class Matches
:first-child An element that is the first child of its parent
:last-child An element that is the last child
:nth-child(2) The second child
:nth-child(odd) / (even) Alternating children
:nth-child(3n) Every third child

Example

<style>
  li:first-child { font-weight: bold; color: #0d6efd; }
  li:last-child { color: crimson; }
  li:nth-child(even) { background-color: #eaf5ff; }
</style>

<ul>
  <li>One (first)</li>
  <li>Two</li>
  <li>Three</li>
  <li>Four (last)</li>
</ul>

Output

  • One (first)
  • Two
  • Three
  • Four (last)

Form states

Pseudo-class Matches
:checked A ticked checkbox or selected radio button
:disabled / :enabled Fields that can or cannot be used
:required / :optional Fields with or without required
:invalid / :valid Fields whose content passes or fails validation
:placeholder-shown A field still showing its placeholder

Example

<style>
  input:required { border: 2px solid #0d6efd; }
  input:disabled { background-color: #e9ecef; }
  input:user-invalid { border-color: crimson; }
  input:checked + label { font-weight: bold; color: #146c43; }
</style>

<p><input type="email" required placeholder="Required email"></p>
<p><input type="text" disabled value="Disabled"></p>
<p><input type="checkbox" id="ok"> <label for="ok">Tick me</label></p>

:invalid matches an empty required field straight away, which can look rude before anyone has typed. :user-invalid waits until the visitor has interacted with the field, so it is friendlier. It is supported by current major browsers, but check older ones if you need to support them.

Negation and grouping

  • :not(selector) matches everything except the selector.
  • :is(a, b, c) matches any of the listed selectors, which shortens long lists.

Example

<style>
  li:not(:last-child) { border-bottom: 1px solid #cfe6ff; }
  :is(h1, h2, h3) { color: #082b59; }
</style>

<h3>Shopping list</h3>
<ul>
  <li>Bread</li>
  <li>Milk</li>
  <li>Eggs</li>
</ul>

Output

Shopping list

  • Bread
  • Milk
  • Eggs

Common mistakes

  • Using two colons (::hover). Pseudo-classes use one; pseudo-elements use two.
  • Adding a space before the colon: a :hover means something different from a:hover.
  • Relying on hover alone. Touch screens have no hover, so important information must be visible without it.
  • Removing focus styles and leaving keyboard users lost.

Exercise

Make every list item show a #eaf5ff background on hover, and make the first item bold.

Show solution
<style>
  li:hover { background-color: #eaf5ff; }
  li:first-child { font-weight: bold; }
</style>
<ul>
  <li>Home</li>
  <li>About</li>
  <li>Contact</li>
</ul>

Knowledge check

1. How many colons does a pseudo-class use?

One.

2. Which pseudo-class selects every other row?

:nth-child(even) or :nth-child(odd).

3. Which pseudo-class matches everything except a given selector?

:not()

Summary

  • Pseudo-classes target states and positions.
  • Use :hover, :focus-visible, :nth-child(), and form-state selectors.
  • :not() and :is() make selectors shorter and clearer.
Scroll to Top