Pseudo-class Selectors
State selectors, structural selectors, and interactive states.
Overview
Pseudo-classes select elements based on state or position.
Key Concepts
- Hover/Active/Focus — Interactive states
- nth-child — Structural selection
- :has() — Parent selector
- :is() — Matches any selector
- :where() — Low specificity matching
Code Examples
/* Interactive states */
.button:hover {
background: var(--primary-dark);
}
.button:active {
transform: scale(0.98);
}
.input:focus {
border-color: var(--primary);
outline: none;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
.input:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}
/* :has() selector */
.form-group:has(:invalid) {
border-color: red;
}
.form-group:has(:focus) {
border-color: var(--primary);
}
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
}
/* Structural selectors */
.list-item:first-child {
border-radius: 8px 8px 0 0;
}
.list-item:last-child {
border-radius: 0 0 8px 8px;
}
.list-item:nth-child(odd) {
background: #f9f9f9;
}
.list-item:nth-child(3n+1) {
clear: both;
}
/* :is() and :where() */
:is(h1, h2, h3) {
font-weight: bold;
line-height: 1.2;
}
:where(.button, .link) {
cursor: pointer;
transition: all 0.2s ease;
}
/* State selectors */
.checkbox:checked + label {
color: var(--primary);
}
.input:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.input:read-only {
background: #f5f5f5;
}
/* Empty state */
.list:empty::before {
content: 'No items found';
color: #999;
}
/* Validation states */
.input:valid {
border-color: green;
}
.input:invalid {
border-color: red;
}
.input:placeholder-shown {
opacity: 0.5;
}
/* Language selectors */
:lang(en) {
font-family: serif;
}
:lang(ar) {
direction: rtl;
}
/* Link states */
a:not([href]) {
color: #999;
pointer-events: none;
}
.visited-link:visited {
color: purple;
}
Practice
Style a form using only pseudo-class selectors.