Pseudo-classes and pseudo-elements let you style things you cannot target with normal selectors — interaction states, specific items in a list, and decorative content generated by CSS itself. They are everywhere in professional CSS.
Pseudo-classes: styling states
A pseudo-class targets an element in a particular state, written with a single colon. You already met <code>:hover</code> and <code>:focus</code>. Others select by position or condition: <code>:first-child</code>, <code>:last-child</code>, <code>:nth-child()</code>, <code>:not()</code> and <code>:checked</code>.
| Pseudo-class | Selects |
|---|---|
| :hover / :focus | Mouse over / keyboard focus |
| :nth-child(odd) | Every odd item (zebra stripes) |
| :first-child / :last-child | First / last in a parent |
| :not(.x) | Everything except .x |
| :checked | A checked checkbox or radio |
<ul class="list"><li>One</li><li>Two</li><li>Three</li><li>Four</li></ul>.list{list-style:none;padding:0}
.list li{padding:10px 14px}
.list li:nth-child(odd){background:#e0f2fe}
.list li:hover{background:#bae6fd}Pseudo-elements: generated content
A pseudo-element, written with two colons, styles a specific part of an element or inserts content. <code>::before</code> and <code>::after</code> add generated content (they need a <code>content</code> property). They are perfect for icons, decorations and badges without extra HTML.
<p class="tip">Pro tip text here</p>.tip{padding:10px 14px;background:#fef3c7;border-radius:8px}
.tip::before{content:'💡 ';}A common real use: custom underlines
<a href="#" class="link">Fancy link</a>.link{position:relative;text-decoration:none;color:#2563eb}
.link::after{content:'';position:absolute;left:0;bottom:-3px;width:100%;height:2px;background:#2563eb;transform:scaleX(0);transition:transform .2s}
.link:hover::after{transform:scaleX(1)}.tip::before { color: red; }.tip::before { content: ''; color: red; }Forgetting the content property on ::before / ::after — without it, nothing renders at all (even content: "" is required).
Use single colon for pseudo-classes (:hover) and double for pseudo-elements (::before) — the double-colon syntax makes the distinction clear. Reach for ::before/::after for decoration so your HTML stays clean.
Make a list with zebra striping using :nth-child(odd), then add a ::before icon to a "note" paragraph, and build an animated underline link using ::after.
1. Which selects every odd list item?
2. What is required on ::before to render?
3. Pseudo-elements use…
- Pseudo-classes (:hover, :nth-child) target states and positions.
- Pseudo-elements (::before, ::after) add generated content — content is required.
- Use them for decoration so your HTML stays clean.
- Single colon = pseudo-class, double colon = pseudo-element.