CSS Pseudo-Classes vs Pseudo-Elements Explained

Pseudo-classes and pseudo-elements look similar (both use colons) but target fundamentally different things — a state versus a generated part of an element.

/* Pseudo-CLASSES: select an element based on its state (single colon) */
a:hover { color: blue; }
input:checked { }
li:nth-child(2) { }
form:invalid { border-color: red; }

/* Pseudo-ELEMENTS: select a part of an element, or generate content (double colon) */
p::first-line { font-weight: bold; }
.quote::before { content: '"'; }
.quote::after { content: '"'; }
input::placeholder { color: #999; }
::selection { background: yellow; }

The single-vs-double-colon convention (:hover vs ::before) was introduced in CSS3 to formally distinguish the two, though browsers still accept the old single-colon syntax for pseudo-elements for backward compatibility — worth using the double colon in new code regardless, since it’s clearer about intent.