CSS Pseudo-classes and Pseudo-elements

CSS pseudo-classes style an element in a particular state, like when it is hovered or is the first child. CSS pseudo-elements style a part of an element, or insert decorative content with ::before and ::after.

State Pseudo-classes

:hover applies while the pointer is over the element, :focus when it has keyboard focus, and :active while it is being clicked. Always style :focus-visible so keyboard users can see where they are.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS Example</title>
<style>
button { padding: 10px 18px; border: 0; border-radius: 6px; background: #2563eb; color: white; font-size: 16px; cursor: pointer; }
button:hover { background: #1d4ed8; }
button:active { transform: scale(0.96); }
button:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
input:focus { border-color: #2563eb; outline: none; box-shadow: 0 0 0 3px rgb(37 99 235 / 30%); }
</style>
</head>
<body>
<button>Hover, click or Tab to me</button>
<p><input placeholder="Click into me"></p>
</body>
</html>

Structural Pseudo-classes

  • :first-child and :last-child
  • :nth-child(2), :nth-child(odd), :nth-child(3n)
  • :not(.active) matches everything except .active
  • :has(img) matches elements that contain an img (modern browsers)

Zebra Striped List

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS Example</title>
<style>
li { padding: 8px; list-style: none; font-family: sans-serif; }
li:nth-child(odd) { background: #f1f5f9; }
li:first-child { font-weight: bold; }
li:not(:last-child) { border-bottom: 1px solid #cbd5e1; }
</style>
</head>
<body>
<ul><li>Name</li><li>Ali</li><li>Sara</li><li>John</li><li>Maria</li></ul>
</body>
</html>

::before and ::after

These pseudo-elements insert content before or after an element's content. They need a content property, even if it is an empty string.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS Example</title>
<style>
.required::after { content: " *"; color: red; }
.quote::before { content: "\201C"; font-size: 40px; color: #94a3b8; vertical-align: -14px; }
p::first-letter { font-weight: bold; }
</style>
</head>
<body>
<label class="required">Email</label>
<p class="quote">Simple things should be simple.</p>
</body>
</html>

Frequently asked questions

What is the difference between a pseudo-class and a pseudo-element?

A pseudo-class (one colon) selects an element in a state, like :hover. A pseudo-element (two colons) selects or creates a part of an element, like ::before.

Why is my ::before not showing?

It needs a content property, for example content: "". Also note that img and input elements cannot have ::before or ::after.

How does nth-child work?

nth-child(n) matches elements by their position among siblings, starting at 1. Use odd, even, or formulas like 3n+1.