🎪 CSS Pseudo-classes & Pseudo-elements

Master advanced selectors for state-based and virtual element styling

← Back to Content Next Topic: Attribute Selectors →

🎯 What are Pseudo-classes and Pseudo-elements?

Pseudo-classes select elements based on their state or position, while pseudo-elements let you style specific parts of elements or create virtual elements.

Key Differences:

  • Pseudo-class: Uses single colon :hover
  • Pseudo-element: Uses double colon ::before
  • ✅ Pseudo-classes target element states or positions
  • ✅ Pseudo-elements create or target parts of elements
  • ✅ Both are powerful selectors for advanced styling

🖱️ Interactive Pseudo-classes

These pseudo-classes respond to user interactions.

1. :hover

/* Style on mouse hover */
button:hover {
    background-color: #667eea;
    transform: scale(1.05);
}

a:hover {
    color: red;
    text-decoration: underline;
}

2. :active

/* Style when being clicked */
button:active {
    transform: scale(0.95);
    box-shadow: inset 0 2px 5px rgba(0,0,0,0.3);
}

3. :focus

/* Style when focused (keyboard/click) */
input:focus {
    outline: 2px solid #667eea;
    border-color: #667eea;
}

/* Better focus with focus-visible (keyboard only) */
button:focus-visible {
    outline: 3px solid #667eea;
    outline-offset: 2px;
}

Interactive Example:

Hover, click, and focus on the button to see effects

4. :visited (Links Only)

/* Visited links */
a:visited {
    color: purple;
}

/* Link states in order (LVHA) */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; }
a:active { color: orange; }

📋 Structural Pseudo-classes

Select elements based on their position in the document structure.

Child Selectors:

/* First child */
li:first-child {
    font-weight: bold;
}

/* Last child */
li:last-child {
    border-bottom: none;
}

/* Only child (no siblings) */
p:only-child {
    text-align: center;
}

/* Nth child */
li:nth-child(2) {        /* Second item */
    color: red;
}

li:nth-child(odd) {      /* 1st, 3rd, 5th... */
    background: #f0f0f0;
}

li:nth-child(even) {     /* 2nd, 4th, 6th... */
    background: white;
}

li:nth-child(3n) {       /* Every 3rd: 3, 6, 9... */
    color: blue;
}

li:nth-child(3n+1) {     /* 1st, 4th, 7th... */
    color: green;
}

Nth-child Example:

  • Item 1 (odd)
  • Item 2 (even)
  • Item 3 (odd)
  • Item 4 (even)
  • Item 5 (odd)

Type Selectors:

/* First of type */
p:first-of-type {
    font-size: 1.2em;
}

/* Last of type */
p:last-of-type {
    margin-bottom: 0;
}

/* Nth of type */
p:nth-of-type(2) {
    color: blue;
}

/* Only of type */
p:only-of-type {
    text-align: center;
}

📝 Form Pseudo-classes

Target form elements based on their state.

/* Enabled/Disabled */
input:enabled {
    background: white;
}

input:disabled {
    background: #f0f0f0;
    cursor: not-allowed;
}

/* Checked (checkbox/radio) */
input:checked {
    accent-color: #667eea;
}

input:checked + label {
    font-weight: bold;
    color: #667eea;
}

/* Required/Optional */
input:required {
    border-left: 3px solid red;
}

input:optional {
    border-left: 3px solid gray;
}

/* Valid/Invalid */
input:valid {
    border-color: green;
}

input:invalid {
    border-color: red;
}

/* In range / Out of range */
input:in-range {
    border-color: green;
}

input:out-of-range {
    border-color: red;
}

/* Placeholder shown */
input:placeholder-shown {
    border-color: #ccc;
}

Form States Example:

🔧 Other Useful Pseudo-classes

/* Not selector (exclude) */
li:not(.special) {
    color: gray;
}

button:not(:disabled) {
    cursor: pointer;
}

/* Empty (no children or text) */
div:empty {
    display: none;
}

/* Root element (html) */
:root {
    --primary-color: #667eea;
}

/* Target (URL anchor) */
:target {
    background: yellow;
    border: 2px solid orange;
}

✨ Pseudo-elements

Pseudo-elements create virtual elements or target specific parts of elements.

1. ::before and ::after

/* Add content before element */
h2::before {
    content: "→ ";
    color: #667eea;
    font-weight: bold;
}

/* Add content after element */
h2::after {
    content: " ←";
    color: #764ba2;
}

/* Decorative elements */
.quote::before {
    content: """;
    font-size: 3em;
    color: #667eea;
}

/* Icons using Unicode */
.link::before {
    content: "🔗 ";
}

/* Required asterisk */
label.required::after {
    content: " *";
    color: red;
}

::before and ::after Example:

Heading with Decorations

2. ::first-letter

/* Style first letter (drop cap) */
p::first-letter {
    font-size: 3em;
    font-weight: bold;
    color: #667eea;
    float: left;
    line-height: 1;
    margin-right: 5px;
}

::first-letter Example:

L orem ipsum dolor sit amet, consectetur adipiscing elit. This paragraph demonstrates the drop cap effect using the ::first-letter pseudo-element.

3. ::first-line

/* Style first line */
p::first-line {
    font-weight: bold;
    color: #667eea;
    text-transform: uppercase;
}

4. ::selection

/* Style selected text */
::selection {
    background: #667eea;
    color: white;
}

/* Firefox */
::-moz-selection {
    background: #667eea;
    color: white;
}

::selection Example:

Try selecting this text! The selection highlight will be styled. (Note: In this demo, default selection styling applies, but in your CSS you can customize it)

5. ::placeholder

/* Style placeholder text */
input::placeholder {
    color: #999;
    font-style: italic;
    opacity: 0.7;
}

💼 Practical Real-World Examples

Example 1: Styled Quote

.quote {
    position: relative;
    padding: 30px 20px 20px 60px;
    background: #f8f9fa;
    border-left: 4px solid #667eea;
}

.quote::before {
    content: """;
    position: absolute;
    top: 10px;
    left: 10px;
    font-size: 4rem;
    color: #667eea;
    opacity: 0.3;
    font-family: Georgia, serif;
}

Example 2: Tooltip

.tooltip {
    position: relative;
    cursor: help;
}

.tooltip::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    padding: 8px 12px;
    background: #333;
    color: white;
    border-radius: 4px;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s;
}

.tooltip:hover::after {
    opacity: 1;
}

Example 3: Badge Counter

.notification {
    position: relative;
}

.notification::after {
    content: attr(data-count);
    position: absolute;
    top: -8px;
    right: -8px;
    background: red;
    color: white;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: bold;
}

Example 4: Custom Checkbox

/* Hide default checkbox */
input[type="checkbox"] {
    display: none;
}

/* Custom checkbox */
input[type="checkbox"] + label::before {
    content: "";
    display: inline-block;
    width: 20px;
    height: 20px;
    border: 2px solid #667eea;
    border-radius: 3px;
    margin-right: 8px;
    vertical-align: middle;
}

/* Checked state */
input[type="checkbox"]:checked + label::before {
    background: #667eea;
    content: "✓";
    color: white;
    text-align: center;
    line-height: 20px;
}

Example 5: Clearfix

/* Classic clearfix */
.clearfix::after {
    content: "";
    display: table;
    clear: both;
}

Example 6: Striped Table

/* Alternating row colors */
tr:nth-child(odd) {
    background: #f8f9fa;
}

tr:nth-child(even) {
    background: white;
}

tr:hover {
    background: #e3f2fd;
}

🔗 Combining Pseudo-classes and Pseudo-elements

/* Hover effect on pseudo-element */
button:hover::before {
    transform: scale(1.2);
}

/* First child's before element */
li:first-child::before {
    content: "👑 ";
}

/* Checked state with after element */
input:checked + label::after {
    content: " ✓";
    color: green;
}

/* Focus visible with custom outline */
button:focus-visible::before {
    content: "";
    position: absolute;
    inset: -4px;
    border: 2px solid #667eea;
    border-radius: inherit;
}

🎨 Live Examples

Hover Effects:

Striped List:

  • First Item
  • Second Item
  • Third Item
  • Fourth Item

Decorative Heading:

Beautiful Title

📝 Test Your Knowledge - MCQ

Q1: What's the difference between : and :: in selectors?

Q2: Which pseudo-class selects every other row?

Q3: What is required for ::before and ::after to work?

Q4: Which pseudo-class targets focused elements?

Q5: What does :not(.class) do?

💪 Practice Questions

  1. Create a button with hover, active, and focus states (different colors for each).
  2. Style a list where every odd item has a light gray background using :nth-child.
  3. Add a decorative icon before all headings using ::before with content property.
  4. Create custom styling for selected text using ::selection with purple background.
  5. Style form inputs to show green border when :valid and red border when :invalid.

📌 Summary

  • Pseudo-class: Single colon (:), targets element states or positions
  • Pseudo-element: Double colon (::), creates/targets parts of elements
  • :hover: When mouse hovers over element
  • :active: When element is being clicked
  • :focus: When element has keyboard/click focus
  • :first-child: First child of parent
  • :last-child: Last child of parent
  • :nth-child(n): Specific child (odd, even, 3n, 3n+1, etc.)
  • :not(): Excludes matching elements
  • ::before/::after: Creates virtual elements (requires content property)
  • ::first-letter: Styles first letter (drop cap)
  • ::first-line: Styles first line
  • ::selection: Styles selected text
  • ::placeholder: Styles input placeholder text
  • Best Practice: Use pseudo-classes for interactivity, pseudo-elements for decorations
← Back to Content Next Topic: Attribute Selectors →