Pseudo-classes and pseudo-elements let CSS target things that are not always represented by a normal class. Pseudo-classes target state or position, while pseudo-elements target a part of an element or create virtual decorative content.
They are powerful because they keep HTML cleaner. You can style hover, focus, checked inputs, first list items, placeholder text, markers, and decorative icons without adding extra wrapper elements.
Pseudo-classes select elements based on their state or structural position. They use a single colon : prefix.
State pseudo-classes such as :hover, :focus-visible, and :disabled respond to interaction. Structural pseudo-classes such as :first-child and :nth-child() respond to where an element sits in the document.
/* === STATE PSEUDO-CLASSES === */
a:link { color: #3498db; }
a:visited { color: #9b59b6; }
a:hover { color: #2980b9; }
a:active { color: #e74c3c; }
a:focus { outline: 2px solid #3498db; }
input:focus { border-color: #3498db; box-shadow: 0 0 0 3px rgba(52,152,219,0.2); }
input:disabled { opacity: 0.5; cursor: not-allowed; }
input:checked { accent-color: #3498db; }
input:valid { border-color: #2ecc71; }
input:invalid { border-color: #e74c3c; }
input:required { border-left: 3px solid #e74c3c; }
input:placeholder-shown { background: #fffde7; }
/* === STRUCTURAL PSEUDO-CLASSES === */
li:first-child { font-weight: bold; }
li:last-child { border-bottom: none; }
li:nth-child(2) { background: #f0f0f0; }
li:nth-child(odd) { background: #fff; }
li:nth-child(even) { background: #f9f9f9; }
li:nth-child(3n) { color: red; } /* every 3rd */
li:nth-child(3n+1) { color: blue; } /* 1st, 4th, 7th... */
p:first-of-type { font-size: 1.1em; }
p:last-of-type { margin-bottom: 0; }
p:only-child { text-align: center; }
p:empty { display: none; }
/* === LOGICAL PSEUDO-CLASSES === */
/* :not() - exclude elements */
li:not(:last-child) { border-bottom: 1px solid #eee; }
input:not([type="submit"]):not([type="reset"]) { border: 1px solid #ccc; }
/* :is() - match any in list (takes highest specificity) */
:is(h1, h2, h3, h4) { font-family: 'Georgia', serif; }
/* :where() - same as :is() but ZERO specificity */
:where(h1, h2, h3) { margin-top: 0; }
/* :has() - parent selector (CSS4) */
.card:has(img) { padding: 0; } /* card with image: no padding */
form:has(input:invalid) .submit-btn { opacity: 0.5; }
/* :focus-within - parent when child is focused */
.form-group:focus-within label { color: #3498db; }
Pseudo-elements style a specific part of an element or insert virtual content. They use a double colon :: prefix.
Generated content from ::before and ::after should normally be decorative. If the content is essential for understanding the page, put it in the HTML so assistive technology and copy/paste behavior remain reliable.
/* ::before - insert content before element */
.required::before {
content: "* ";
color: red;
}
/* ::after - insert content after element */
.price::after {
content: " USD";
font-size: 0.8em;
color: gray;
}
/* Decorative elements with ::before/::after */
.section-title::after {
content: '';
display: block;
width: 60px;
height: 3px;
background: #3498db;
margin-top: 8px;
}
/* ::first-letter - drop cap */
article p:first-of-type::first-letter {
font-size: 3em;
font-weight: bold;
float: left;
line-height: 0.8;
margin: 0 8px 0 0;
color: #3498db;
}
/* ::first-line */
p::first-line {
font-weight: bold;
color: #2c3e50;
}
/* ::selection - selected text */
::selection {
background-color: #3498db;
color: white;
}
/* ::placeholder */
input::placeholder {
color: #aaa;
font-style: italic;
}
/* ::marker - list item marker */
li::marker {
color: #3498db;
font-size: 1.2em;
}
/* ::backdrop - behind fullscreen elements */
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
.lesson-box:empty::before {
content: "CSS Pseudo Classes Elements hover before: add visible content";
}
A pseudo-class selects an element state or position. A pseudo-element styles part of an element or generated content.
:focus-visible is usually better for custom keyboard focus styles because it avoids showing focus rings for many mouse interactions.
They need the content property, even if it is an empty string.
Explore 500+ free tutorials across 20+ languages and frameworks.