CSS course menu
CSS Pseudo-classes: :hover, :focus, :nth-child, :not and More
Learn CSS pseudo-classes with live examples: user action states (:hover, :focus, :focus-visible, :active), link states, form states (:checked, :disabled, :invalid, :user-invalid), structural pseudo-classes (:first-child, :nth-child, :nth-of-type) and :not().
On this page
A pseudo-class selects elements in a particular state or position: a link being hovered, a field with an invalid value, the first item in a list. Pseudo-classes start with a single colon.
User action states#
.btn {
padding: 8px 16px;
background: #2f5fe0;
color: white;
border: none;
border-radius: 6px;
}
.btn:hover { background: #1f45b0; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 3px solid orange; outline-offset: 2px; }<button class="btn">Hover, click, or Tab to me</button>Link states#
a:link { color: #2f5fe0; }
a:visited { color: #7a3fb8; }
a:hover { text-decoration: none; }<p><a href="https://example.com/never-visited-page-123">A link</a></p>If you style several link states, keep the order :link, :visited, :hover, :active (some people remember it as "LoVe HAte"), because later rules win when specificity is equal. For privacy, browsers only let :visited change colours.
Form states#
input:disabled { background: #eee; }
input:checked + label { font-weight: bold; color: green; }
input:required { border-left: 4px solid #2f5fe0; }
input:user-invalid { border-color: red; outline: 1px solid red; }<p><input type="checkbox" id="t1"> <label for="t1">Tick me</label></p>
<p><input type="text" placeholder="Disabled" disabled></p>
<p><input type="email" placeholder="Type an invalid email, then click away" required size="35"></p>:checkedmatches ticked checkboxes, selected radio buttons and selected options.:disabled/:enabled,:required/:optional,:read-only.:valid/:invalidmatch by validation state immediately, even before the user types.:user-invalidonly matches after the user has interacted with the field, which is friendlier. It is supported in current versions of all major browsers.:placeholder-shownmatches while the placeholder is visible.
Structural pseudo-classes#
These select elements by their position among siblings:
li:first-child { color: green; }
li:last-child { color: crimson; }
li:nth-child(even) { background: #f0f0f0; }<ul>
<li>First</li>
<li>Second</li>
<li>Third</li>
<li>Fourth</li>
<li>Fifth (last)</li>
</ul>nth-child versus nth-of-type#
p:nth-child(2) means "the second child, if it is a p". p:nth-of-type(2) means "the second p, ignoring other element types":
p:nth-child(2) { background: #fde2e2; }
p:nth-of-type(2) { outline: 2px solid #2f5fe0; }<div>
<h3>Title</h3>
<p>First paragraph (second child: pink)</p>
<p>Second paragraph (second p: outlined)</p>
</div>:not()#
:not() matches elements that do not match the selector inside:
.tags span:not(:last-child)::after { content: ", "; }<p class="tags"><span>html</span><span>css</span><span>javascript</span></p>Commas appear after every tag except the last. :not() accepts a list of selectors, for example :not(.active, .disabled).
The newer :is(), :where() and :has() pseudo-classes are covered in Modern Selectors.
Practice#
Practice exercise
Style a table so its body rows are zebra-striped (every even row light grey), a row turns light yellow when hovered, and the first column is bold.
Show solution
table { border-collapse: collapse; }
td { padding: 6px 12px; }
tbody tr:nth-child(even) { background: #f2f2f2; }
tbody tr:hover { background: #fff8c4; }
td:first-child { font-weight: bold; }<table>
<tbody>
<tr><td>Asha</td><td>92</td></tr>
<tr><td>Ravi</td><td>87</td></tr>
<tr><td>Meera</td><td>95</td></tr>
<tr><td>Kiran</td><td>78</td></tr>
</tbody>
</table>Key takeaway#
Finished this lesson?