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.
- ✓Pseudo-classes use a single colon — like :hover — and target an element's state or position.
- ✓Pseudo-elements use a double colon — like ::before — and target a part of an element, sometimes one that doesn't exist until CSS creates it.
- ✓Both attach directly to a selector with no space: a:hover, li:first-child, p::before.
: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.
.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; }
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.
The first element among its siblings.
The last element among its siblings.
A specific position, or a pattern — nth-child(even), nth-child(3n).
An element that is the sole child of its parent.
/* Zebra-stripe a list without adding a single class */ li:nth-child(even) { background: #fdefe4; }
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.
/* 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; }
::placeholder, ::selection & ::first-letter
Beyond ::before and ::after, a handful of pseudo-elements target specific browser-rendered parts of an element.
The hint text shown inside an empty input before typing.
Text as it appears while the user is highlighting it.
Just the first letter of a block of text — handy for drop caps.
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.
Breaking Down What You Just Learned
One colon vs twoPseudo-classes use : (hover, first-child) — pseudo-elements use :: (before, after, placeholder).
Interactive states:hover, :focus-visible, and :active respond to how someone is interacting with an element.
Structural selection:first-child, :last-child, and :nth-child(n) select by position — no extra class required.
Generated content::before and ::after need a content property to render anything at all.
Use decorativelyGenerated pseudo-element content is invisible to screen readers — keep real content in the HTML.
Try It Yourself
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
Practicing pseudo-classes and pseudo-elements together
Create day21.html linked to a stylesheet and build the following on the page.
- Build a <ul> of at least five items and zebra-stripe it using li:nth-child(even).
- Style a link or button with distinct :hover, :focus-visible, and :active states.
- Add a ::before quote mark to a blockquote or testimonial-style paragraph.
- Add a ::after "NEW" or "SALE" badge to a product or course card.
- Style an <input>'s ::placeholder text in a color that matches your palette.
Recap
:hover, :focus-visible, and :active respond to how the user is engaging with an element.
:first-child, :last-child, and :nth-child(n) select elements by position among siblings.
::before and ::after insert virtual elements — always need a content property.
::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.