~/hackweb.dev
CSS Selectors
Quiz
...

CSS Selectors

beginner · updated Tue Sep 08 2026Contribute

Master combinators, pseudo-classes, pseudo-elements, and advanced selectors.

CSS Selectors

Selectors target HTML elements for styling. The more specific your selector, the more control you have.

Basic Selectors Review

/* Element selector */
p { }

/* Class selector */
.highlight { }

/* ID selector */
#header { }

/* Universal selector */
* { }

/* Grouping selector */
h1, h2, h3 { }

Combinators

Combine selectors to target specific relationships:

Descendant Selector (space)

Targets all descendants (children, grandchildren, etc.):

/* All <p> inside <div> */
div p {
  color: blue;
}

Child Selector ( > )

Targets only direct children:

/* Only <p> that are direct children of <div> */
div > p {
  color: blue;
}

Adjacent Sibling ( + )

Targets the immediately following sibling:

/* <p> immediately after <h1> */
h1 + p {
  font-size: 1.2em;
}

General Sibling ( ~ )

Targets all following siblings:

/* All <p> after <h1> */
h1 ~ p {
  color: gray;
}

Attribute Selectors

Target elements based on attributes:

/* Elements with href attribute */
a[href] {
  color: blue;
}

/* Exact match */
a[href="https://example.com"] {
  color: red;
}

/* Contains word */
a[href~="example"] {
  color: green;
}

/* Starts with */
a[href^="https"] {
  color: green;
}

/* Ends with */
a[href$=".pdf"] {
  color: red;
}

/* Contains substring */
a[href*="example"] {
  color: purple;
}

Pseudo-Classes

Target elements in specific states:

/* Unvisited link */
a:link {
  color: blue;
}

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

/* Hover state */
a:hover {
  color: red;
}

/* Active (clicked) state */
a:active {
  color: orange;
}

/* Focus state (keyboard navigation) */
a:focus {
  outline: 2px solid blue;
}

Order matters: L-V-H-A (Link, Visited, Hover, Active)

Structural Pseudo-Classes

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

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

/* nth-child (position) */
li:nth-child(2) {
  color: red;
}

/* nth-child (formula) */
li:nth-child(odd) {
  background-color: #f5f5f5;
}

li:nth-child(3n) {
  font-size: 1.2em;
}

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

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

/* Only child */
.item:only-child {
  margin: 0 auto;
}

/* Empty element */
div:empty {
  display: none;
}

Form Pseudo-Classes

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

/* Optional field */
input:optional {
  border-left: 3px solid gray;
}

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

/* Invalid input */
input:invalid {
  border-color: red;
}

/* Checked checkbox/radio */
input:checked {
  accent-color: blue;
}

/* Disabled input */
input:disabled {
  background-color: #eee;
  cursor: not-allowed;
}

/* Enabled input */
input:enabled {
  background-color: white;
}

/* Placeholder shown */
input:placeholder-shown {
  color: gray;
}

Pseudo-Elements

Target specific parts of elements:

/* First line of text */
p::first-line {
  font-weight: bold;
}

/* First letter */
p::first-letter {
  font-size: 2em;
  float: left;
}

/* Before content */
h1::before {
  content: "★ ";
  color: gold;
}

/* After content */
h1::after {
  content: " ★";
  color: gold;
}

/* Selected text */
::selection {
  background-color: yellow;
  color: black;
}

/* Placeholder text */
input::placeholder {
  color: gray;
  font-style: italic;
}

Complete Example

/* Style all links */
a {
  color: #3498db;
  text-decoration: none;
  transition: color 0.3s;
}

/* Style links on hover */
a:hover {
  color: #2980b9;
  text-decoration: underline;
}

/* Style first paragraph in article */
article > p:first-of-type {
  font-size: 1.2em;
  line-height: 1.8;
}

/* Style even rows in table */
tr:nth-child(even) {
  background-color: #f9f9f9;
}

/* Style required inputs */
input:required {
  border-left: 3px solid #e74c3c;
}

/* Add quotes to blockquotes */
blockquote::before {
  content: open-quote;
  font-size: 3em;
  color: #ccc;
  line-height: 0;
  margin-right: 0.25em;
  vertical-align: -0.4em;
}

/* Style list items */
li:not(:last-child) {
  border-bottom: 1px solid #eee;
  padding-bottom: 10px;
  margin-bottom: 10px;
}

/* Style empty divs */
div:empty {
  display: none;
}

/* Style focused inputs */
input:focus {
  outline: none;
  border-color: #3498db;
  box-shadow: 0 0 5px rgba(52, 152, 219, 0.5);
}

Selector Specificity

CSS follows specificity rules when multiple selectors match:

/* Specificity (low to high): */
/* 1. Element selectors (p, div, span) */
/* 2. Class selectors (.class) */
/* 3. ID selectors (#id) */
/* 4. Inline styles (style="") */
/* 5. !important */

p { color: black; }           /* Specificity: 1 */
.text { color: blue; }        /* Specificity: 10 */
#header { color: red; }       /* Specificity: 100 */

Complete HTML Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      /* Descendant selector */
      .nav a {
        display: inline-block;
        padding: 10px 20px;
        color: white;
        text-decoration: none;
      }

      /* Hover state */
      .nav a:hover {
        background-color: #3498db;
      }

      /* nth-child */
      .list li:nth-child(odd) {
        background-color: #f5f5f5;
      }

      /* Pseudo-element */
      .quote::before {
        content: open-quote;
        font-size: 2em;
      }

      .quote::after {
        content: close-quote;
        font-size: 2em;
      }

      /* Attribute selector */
      a[href^="https"]::after {
        content: " ↗";
        font-size: 0.8em;
      }
    </style>
  </head>
  <body>
    <nav class="nav">
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="https://example.com">External</a>
    </nav>

    <ul class="list">
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      <li>Item 4</li>
    </ul>

    <blockquote class="quote">
      This is a quoted text.
    </blockquote>
  </body>
</html>

Best Practices

  1. Keep selectors simple — Avoid overly specific selectors
  2. Use classes — More reusable than IDs
  3. Avoid !important — Use specificity instead
  4. Use BEM naming.block__element--modifier
  5. Test in multiple browsers — Ensure compatibility

Common Mistakes

  1. Overly specific selectors#main > div > ul > li > a is too specific
  2. Using !important — Overrides specificity rules
  3. Forgetting link order — L-V-H-A order matters
  4. Not using pseudo-classes — Miss hover states
  5. Overusing IDs — Hard to override later