MODULE 03 · CSS FOUNDATIONS

Pseudo-classes & Pseudo-elements

Not everything worth styling has its own class in the HTML. Pseudo-classes target elements based on state or position, and pseudo-elements let you style — or even create — parts of an element that don't exist in the markup.

Day 21 of 30 Beginner ~19 min

Styling States, Positions & Invisible Parts

So far, every selector you've written targets something that's already sitting in the HTML. Pseudo-classes and pseudo-elements go a step further — they let CSS react to state (is the mouse over it? has this link been visited?), position (is this the first item in a list?), and even generate content that was never written in the markup at all.

:hover, :focus & :active

These three pseudo-classes respond to how a person is interacting with an element right now — pointer over it, keyboard focus on it, or actively being clicked.

style.css
.btn {
  background: #ffffff;
  color: #b8430a;
  border: 1px solid #e8590c;
  transition: background .15s ease;
}

.btn:hover {
  background: #e8590c;
  color: #ffffff;
}

.btn:focus-visible {
  outline: 3px solid #e85fa0;
}

.btn:active {
  background: #b8430a;
}
TRY IT — HOVER, THEN TAB TO FOCUS, THEN CLICK
.btn:hover / :focus-visible / :active
GOOD TO KNOW

Use :focus-visible instead of :focus when possible — it only shows the outline for keyboard users, not for every mouse click, which keeps the interface clean without sacrificing accessibility.

Targeting by Position

Structural pseudo-classes select elements based on where they sit among their siblings — no extra class needed.

SELECTOR WHAT IT MATCHES
:first-child

The first element among its siblings.

:last-child

The last element among its siblings.

:nth-child(n)

A specific position, or a pattern — nth-child(even), nth-child(3n).

:only-child

An element that is the sole child of its parent.

style.css
/* Zebra-stripe a list without adding a single class */
li:nth-child(even) {
  background: #fdefe4;
}
ZEBRA STRIPING WITH :nth-child(even)
Ananta Creative
BrijLodge Haridwar
Protect Prithvi
Code Academy
Client Project 05

Generating Content With CSS

::before and ::after insert a virtual element just inside the start or end of the element they're attached to. They require a content property — even an empty string — or nothing renders.

style.css
/* A decorative quote mark that isn't in the HTML */
.quote::before {
  content: "“";
  color: #e8590c;
  font-size: 2rem;
}

/* A "NEW" badge pinned to a corner */
.badge::after {
  content: "NEW";
  position: absolute;
  top: -8px;
  right: -10px;
}
::before AND ::after IN ACTION
Small changes here have an immediate, visible effect.
.quote::before
Course Update .badge::after

::placeholder, ::selection & ::first-letter

Beyond ::before and ::after, a handful of pseudo-elements target specific browser-rendered parts of an element.

SELECTOR WHAT IT STYLES
::placeholder

The hint text shown inside an empty input before typing.

::selection

Text as it appears while the user is highlighting it.

::first-letter

Just the first letter of a block of text — handy for drop caps.

::placeholder IN ACTION
input::placeholder

Pseudo-elements Are Decoration, Not Content

Content generated with the content property is invisible to screen readers and can't be selected as real text. It's fine for decorative marks, icons, and visual flourishes — never for information the user actually needs to read.

RIGHT VS WRONG USE
AVOID Putting a price, a warning, or any real content inside a ::before content string — it's invisible to screen readers and can't be copied.
BETTER Use ::before/::after for quote marks, decorative icons, or badges — and keep real content in the actual HTML.

Breaking Down What You Just Learned

1

One colon vs twoPseudo-classes use : (hover, first-child) — pseudo-elements use :: (before, after, placeholder).

2

Interactive states:hover, :focus-visible, and :active respond to how someone is interacting with an element.

3

Structural selection:first-child, :last-child, and :nth-child(n) select by position — no extra class required.

4

Generated content::before and ::after need a content property to render anything at all.

5

Use decorativelyGenerated pseudo-element content is invisible to screen readers — keep real content in the HTML.

Try It Yourself

EXERCISE

Take the card elements you styled on Day 17 and add a :hover state that lifts them slightly with transform, then use ::before to add a small decorative icon in front of each card's heading.

Build an Interactive List & Badge

HANDS-ON EXERCISE

Practicing pseudo-classes and pseudo-elements together

Create day21.html linked to a stylesheet and build the following on the page.

  1. Build a <ul> of at least five items and zebra-stripe it using li:nth-child(even).
  2. Style a link or button with distinct :hover, :focus-visible, and :active states.
  3. Add a ::before quote mark to a blockquote or testimonial-style paragraph.
  4. Add a ::after "NEW" or "SALE" badge to a product or course card.
  5. Style an <input>'s ::placeholder text in a color that matches your palette.

Recap

INTERACTIVE STATES

:hover, :focus-visible, and :active respond to how the user is engaging with an element.

STRUCTURAL

:first-child, :last-child, and :nth-child(n) select elements by position among siblings.

GENERATED CONTENT

::before and ::after insert virtual elements — always need a content property.

OTHER USEFUL ONES

::placeholder, ::selection, and ::first-letter style specific rendered parts of an element.

Key Takeaways

  • Pseudo-classes (single colon) target state or position; pseudo-elements (double colon) target a part of an element.
  • :hover, :focus-visible, and :active let interfaces respond to the user without any JavaScript.
  • :nth-child(n) accepts numbers, keywords like even/odd, or patterns like 3n for repeating selections.
  • ::before and ::after only render when given a content property, even if that value is an empty string.
  • Generated content is decorative and invisible to assistive technology — never hide real information inside it.
Course Overview