Home Module 03 CSS Selectors

1. Introduction

A CSS selector is the part of a CSS rule that says "which HTML element should this style apply to?" Getting selectors right is one of the most important skills in CSS.

Imagine you have a page with 10 paragraphs and you only want to make one of them red. A selector lets you say "style this specific paragraph, not all of them". Without selectors you could only style every paragraph the same way.

CSS has many types of selectors — from very simple ones (target all <h1> elements) to very precise ones (target only the third list item inside a specific <nav>). In this lesson we cover all the essential selectors you will use every day.

2. Theory

Type (Element) Selector

Targets all elements of a given type.

p { color: grey; }       /* all paragraphs */
h1 { font-size: 2rem; } /* all h1 headings */
a { color: blue; }      /* all links */

Class Selector

Targets elements with a specific class attribute. Uses a dot . prefix. You can apply one class to many elements, and one element can have many classes.

/* CSS */
.btn { padding: 10px 20px; }
.btn-primary { background: blue; color: white; }

/* HTML */
<button class="btn btn-primary">Save</button>

ID Selector

Targets one specific element with a matching id. Uses a hash # prefix. IDs must be unique — only one element per page can have a given ID.

/* CSS */
#main-header { background: #1e293b; }

/* HTML */
<header id="main-header">...</header>

Universal Selector

Targets every element on the page. Uses *.

* {
  box-sizing: border-box; /* a very common use case */
  margin: 0;
  padding: 0;
}

Attribute Selector

Targets elements with a specific attribute or attribute value.

a[target="_blank"] { color: orange; }       /* links that open new tab */
input[type="email"] { border: 2px solid blue; } /* email inputs */
[disabled] { opacity: 0.5; }               /* any disabled element */

Pseudo-class Selectors

Target elements in a specific state. Use a single colon :.

Pseudo-classMeaning
:hoverUser's mouse is over the element
:focusElement has keyboard or click focus
:activeElement is being clicked
:visitedLink has been visited
:first-childFirst child of its parent
:last-childLast child of its parent
:nth-child(n)The nth child (e.g. :nth-child(2))
:not(selector)Any element that does NOT match
a:hover { text-decoration: underline; }
li:first-child { font-weight: bold; }
li:nth-child(odd) { background: #f1f5f9; } /* zebra striping */

Pseudo-element Selectors

Target a specific part of an element. Use double colon ::.

p::first-line { font-weight: bold; }         /* first line of paragraph */
p::first-letter { font-size: 2em; }          /* drop cap effect */
.card::before { content: "★ "; color: gold; } /* insert content before */
.card::after  { content: " ✓"; color: green; } /* insert content after */

Combinator Selectors

Target elements based on their relationship to other elements.

CombinatorSyntaxMeaning
DescendantA BB anywhere inside A
ChildA > BB that is a direct child of A
Adjacent siblingA + BB immediately after A
General siblingA ~ BAll B siblings after A
nav a { color: white; }          /* all links inside nav */
nav > ul { list-style: none; }   /* ul that is direct child of nav */
h2 + p { margin-top: 0; }        /* paragraph right after an h2 */

Grouping Selectors

Apply the same styles to multiple selectors by separating them with commas.

h1, h2, h3 { font-family: Georgia, serif; }
.btn, .link { cursor: pointer; }

Specificity

When two rules target the same element, the more specific one wins. Specificity is calculated as:

Selector TypeSpecificity Points
Inline style1000
ID selector100
Class / pseudo-class / attribute10
Type / pseudo-element1
Universal (*)0
#header h1 { color: red; }  /* specificity: 100 + 1 = 101 */
.title { color: blue; }     /* specificity: 10 */
/* #header h1 wins */

3. Real World Example

On a real website, selectors are used constantly:

  • .nav-link:hover — changes colour when you hover over a navigation link
  • input:focus — shows a blue outline when a form field is active
  • .card:nth-child(odd) — alternating background colours in a list
  • button[disabled] — greyed-out button when the form is incomplete
  • .modal > .modal-content — only the direct child content div inside a modal, not all nested divs

4. Code Example

/* === SELECTOR SHOWCASE === */

/* Type selector */
body {
  font-family: Arial, sans-serif;
  background: #f8fafc;
}

/* Class selector */
.card {
  background: white;
  border-radius: 8px;
  padding: 24px;
  margin-bottom: 16px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.1);
}

/* ID selector */
#hero {
  background: #2563eb;
  color: white;
  padding: 80px 40px;
  text-align: center;
}

/* Pseudo-class: hover */
.btn:hover {
  background: #1d4ed8;
  transform: translateY(-1px);
}

/* Pseudo-class: focus (for accessibility) */
a:focus,
button:focus {
  outline: 3px solid #f59e0b;
  outline-offset: 2px;
}

/* Descendant combinator */
.nav ul {
  list-style: none;
  display: flex;
  gap: 16px;
}

/* Child combinator */
.dropdown > .dropdown-menu {
  display: none;
}

.dropdown:hover > .dropdown-menu {
  display: block;
}

/* Attribute selector */
a[href^="https"] {
  /* links starting with https */
  color: green;
}

/* Grouping */
h1, h2, h3, h4 {
  color: #0f172a;
  line-height: 1.2;
}

/* Nth-child: zebra table rows */
tr:nth-child(even) {
  background: #f1f5f9;
}

5. Code Breakdown

box-shadow: 0 1px 4px rgba(0,0,0,0.1);
Adds a soft shadow under the card. 0 = no horizontal offset, 1px = 1px down, 4px = blur radius, rgba(0,0,0,0.1) = black at 10% opacity.
transform: translateY(-1px);
Moves the element 1px upward when hovered — a subtle "lift" effect on buttons. The transform property moves/rotates/scales elements without affecting layout.
a:focus, button:focus
Comma grouping — applies to both a and button when focused. This is essential for keyboard accessibility.
a[href^="https"]
Attribute selector with ^= which means "starts with". Targets only links whose href begins with https. Other operators: $= (ends with), *= (contains).
.dropdown > .dropdown-menu
Child combinator — only the .dropdown-menu that is a direct child of .dropdown. Safer than descendant if menus are nested.

6. Common Mistakes

  • Confusing class and ID. Class uses ., ID uses #. Using the wrong prefix is very common.
    /* Wrong: using # for a class */
    #btn { background: blue; }
    
    /* Correct: class selector for class="btn" */
    .btn { background: blue; }
  • Overusing ID selectors. IDs have very high specificity (100 points), making them hard to override. Prefer class selectors for styling.
  • Not understanding the descendant selector. div p targets ALL paragraphs inside ANY div — even deeply nested ones. Use div > p if you only want direct children.
  • Forgetting ::before and ::after need content:. These pseudo-elements do not display at all unless you include content: ""; (even an empty string).
  • Using * selector everywhere. The universal selector affects all elements and can be a performance concern and cause unexpected overrides. Use it sparingly.

7. Best Practices

  • Prefer class selectors for styling — they are reusable and have manageable specificity.
  • Keep specificity low — avoid chaining many selectors like div#sidebar ul li a span. It becomes very hard to override.
  • Use meaningful class names.nav-link, .card-title, .btn-primary describe purpose, not appearance.
  • Never use !important unless absolutely forced to. It overrides all specificity and creates hard-to-debug CSS wars.
  • Style pseudo-classes for accessibility — always style :focus so keyboard users can see where they are.
  • Use pseudo-elements for decorative content::before and ::after are great for icons, decorations that should not be in the HTML.

8. Practice Exercise

Create selectors.html and selectors.css. In the HTML, create:

  • A <nav> with an unordered list of 4 links
  • Three <div class="card"> elements each with a heading and paragraph
  • A button with id="submit-btn"

In CSS, write rules using:

  1. A type selector to style the body
  2. A class selector to style .card
  3. An ID selector to style #submit-btn
  4. A descendant selector to style links inside nav
  5. A :hover pseudo-class on the button
  6. A :nth-child(odd) to give alternating card backgrounds

9. Assignment

Build a styled navigation menu. Requirements:

  • An HTML <nav> element containing a <ul> with 5 <li> items, each containing an <a> link
  • Style the nav with a dark background using a type selector
  • Use descendant selectors to remove bullet points and set link colour to white
  • Add a :hover style that changes the link background colour
  • Mark the current page link with class="active" and style it differently
  • Add a :focus style for keyboard accessibility

10. Interview Questions

Q1: What is the difference between a class and an ID in CSS?

Answer: A class (.) can be used on multiple elements and one element can have multiple classes. An ID (#) must be unique per page — only one element should have a given ID. IDs have much higher specificity (100) than classes (10), making them harder to override.

Q2: What is CSS specificity?

Answer: Specificity is the algorithm browsers use to decide which CSS rule applies when two rules conflict. It is calculated based on the types of selectors used: inline styles (1000), IDs (100), classes/pseudo-classes/attributes (10), types/pseudo-elements (1). The rule with the higher specificity wins.

Q3: What is the difference between a descendant selector and a child selector?

Answer: A descendant selector (A B — space) matches B anywhere inside A, no matter how deeply nested. A child selector (A > B) only matches B elements that are direct children of A, one level deep.

Q4: What is a pseudo-class? Give three examples.

Answer: A pseudo-class selects an element in a specific state. Examples: :hover (mouse over the element), :focus (element has focus), :nth-child(n) (element is the nth child of its parent).

Q5: How do you target every other table row?

Answer: Use tr:nth-child(even) or tr:nth-child(odd) to style alternating rows — commonly called "zebra striping" to improve table readability.

11. Additional Resources

  • MDN Web Docs — CSS Selectors (search "MDN CSS selectors")
  • CSS Specificity Calculator — specificity.keegan.st
  • CSS Diner — flukeout.github.io (interactive selector practice game)
  • MDN — Pseudo-classes reference (search "MDN CSS pseudo-classes")
  • MDN — Pseudo-elements reference (search "MDN CSS pseudo-elements")