Pseudo-classes & Pseudo-elements

Style elements based on their state or position, and generate virtual content, all without touching HTML.

CSS5 min readConcept 3 of 43

Two kinds of virtual targeting

**Pseudo-classes** select a real element based on its current state or its position in the document tree. They use a single colon: :hover, :focus, :checked, :nth-child(2). No new HTML is written; the browser applies the rule dynamically as state changes.

**Pseudo-elements** create a virtual sub-part of an element that you can style or inject content into. They use a double colon: ::before, ::after, ::first-line, ::placeholder. The ::before and ::after pseudo-elements insert a generated content box directly before or after an element's existing content. They require a content: declaration (even content: '' for decorative shapes).

The historical single-colon syntax for pseudo-elements (:before, :after) still works in most browsers but :: is the standard going forward. Pseudo-classes always use a single colon.

State and structure without extra HTML

Without pseudo-classes you would need JavaScript to add a .hovered class on every mouseover. Pseudo-classes let CSS handle state natively: :hover, :focus, :active, :checked are browser-native and always accurate.

Pseudo-elements let you add decorative content (arrows, badges, underline bars) entirely in CSS without polluting the HTML with presentational <span> tags. A CSS-only tooltip, a custom list bullet, or a quote decoration are all achievable with ::before / ::after.

Common pseudo-classes and pseudo-elements

**State pseudo-classes:** :hover (mouse over), :focus (keyboard or click focus), :active (mouse button held), :visited (link visited), :checked (checkbox or radio), :disabled, :required, :valid, :invalid.

**Structural pseudo-classes:** :first-child, :last-child, :nth-child(n) (e.g. li:nth-child(2n) for even items), :nth-of-type(n), :only-child, :not(selector) (e.g. li:not(:last-child)).

**Pseudo-elements:** ::before and ::after (generated content, require content:), ::first-line (first line of text), ::first-letter (drop cap), ::placeholder (input placeholder text), ::selection (user-selected text highlight), ::marker (list item bullet or number).

Combine with selectors freely: a:hover::after adds content after a link while it is hovered. input:focus::placeholder styles the placeholder only while the input is focused.

Try it

Toggle pseudo-class and pseudo-element chips to see each one applied to a live sample element.

Pseudo-classes

Pseudo-elements

.btn:hover { background: #6d28d9; color: #fff; }

Applied when the pointer is over the element.

Simulated state: ON

Hovered state active

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1Which pseudo-element creates a box before an element's content without adding HTML?
  2. 2Which CSS targets every even `<li>` in a list?
  3. 3What does `:not(.active)` select?

Remember this

  • Pseudo-classes (:hover, :focus, :nth-child) select real elements by state or position.
  • Pseudo-elements (::before, ::after) create virtual sub-parts. Always include content: on ::before/::after.
  • Double colon :: is the modern standard for pseudo-elements; single colon is legacy.
  • :not(), :is(), :where() group or negate selectors cleanly without extra HTML.

Done with this concept?

Mark it complete to track your progress. No login needed.