CSS Selectors 101: Targeting Elements with Precision
Introduction: The Targeting Problem
Imagine you have a classroom with 30 students and you need to give instructions:
Scenario 1: "Everyone, open your textbooks"
→ Targets: ALL students
Scenario 2: "All students wearing blue shirts, stand up"
→ Targets: Students with specific characteristic (blue shirts)
Scenario 3: "Sarah, please come to the front"
→ Targets: ONE specific student by name
CSS selectors work the same way. They let you choose which HTML elements to style.
<h1>Main Title</h1>
<p>First paragraph</p>
<p>Second paragraph</p>
<p class="highlight">Important paragraph</p>
<p id="intro">Introduction paragraph</p>
Questions CSS selectors answer:
- How do I style ALL paragraphs?
- How do I style ONLY the highlighted paragraph?
- How do I style ONLY the intro paragraph?
- How do I style the title?
Without selectors, you can't apply CSS. They're that fundamental.
Why CSS Selectors Are Needed
The Problem: Blind Styling
Imagine CSS without selectors:
/* This doesn't exist! */
color: blue;
font-size: 20px;
Questions that arise:
- Which elements turn blue?
- Which text gets bigger?
- Does it apply to everything?
Answer: We don't know! That's the problem.
The Solution: Selectors
/* NOW we know! */
p {
color: blue;
font-size: 20px;
}
Clear answer:
✓ All <p> elements turn blue
✓ All <p> elements get 20px font size
✓ Other elements (h1, div, etc.) are unaffected
Real-World Analogy: Postal Addresses
┌─────────────────────────────────────────────────────────────┐
│ POSTAL SYSTEM = CSS SELECTORS │
└─────────────────────────────────────────────────────────────┘
Letter delivery:
├── Country (USA) → Element selector (target all <p>)
├── State (California) → More specific
├── City (San Francisco) → Even more specific
├── Street (Main St) → Class selector (target .highlight)
└── House Number (123) → ID selector (target #intro)
The more specific the address, the fewer recipients.
Anatomy of a CSS Rule
Before diving into selectors, understand the CSS structure:
selector {
property: value;
}
Example:
p {
color: blue;
}
Parts:
p → Selector (WHAT to style)
{...} → Declaration block
color → Property (WHICH aspect to style)
blue → Value (HOW to style it)
Visual breakdown:
┌─────────────────────────────────────────────────────────────┐
│ CSS RULE ANATOMY │
└─────────────────────────────────────────────────────────────┘
┌─ Selector: Targets elements
│
p {
color: blue;
│ │
│ └─ Value: What to apply
│
└─ Property: What to change
}
1. Element Selector (Type Selector)
The element selector targets all elements of a specific type.
Syntax
elementname {
/* styles */
}
Examples
/* Target ALL paragraphs */
p {
color: blue;
}
/* Target ALL headings level 1 */
h1 {
font-size: 32px;
}
/* Target ALL divs */
div {
background-color: lightgray;
}
/* Target ALL links */
a {
text-decoration: none;
}
HTML + CSS Example
HTML:
<h1>Welcome</h1>
<p>First paragraph</p>
<p>Second paragraph</p>
<p>Third paragraph</p>
CSS:
p {
color: blue;
font-size: 16px;
}
Result:
┌─────────────────────────────────────────────────────────────┐
│ RENDERED OUTPUT │
└─────────────────────────────────────────────────────────────┘
Welcome ← h1 (not affected)
First paragraph ← p (blue, 16px)
Second paragraph ← p (blue, 16px)
Third paragraph ← p (blue, 16px)
When to Use
✓ Style all elements of one type consistently
✓ Set base styles (all paragraphs, all headings)
✓ Reset default browser styles
Example use cases:
├── Make all links blue
├── Give all paragraphs the same font size
└── Remove underlines from all links
Visual: How Element Selectors Work
┌─────────────────────────────────────────────────────────────┐
│ ELEMENT SELECTOR TARGETING │
└─────────────────────────────────────────────────────────────┘
HTML:
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<div>Box</div>
<p>Paragraph 3</p>
CSS:
p { color: red; }
Targets:
<h1>Title</h1> ✗ (not a <p>)
<p>Paragraph 1</p> ✓ (turns red)
<p>Paragraph 2</p> ✓ (turns red)
<div>Box</div> ✗ (not a <p>)
<p>Paragraph 3</p> ✓ (turns red)
2. Class Selector
The class selector targets elements with a specific class attribute.
Syntax
.classname {
/* styles */
}
Note the dot (.) prefix!
HTML Setup
<p>Normal paragraph</p>
<p class="highlight">Highlighted paragraph</p>
<p class="highlight">Another highlighted paragraph</p>
<div class="highlight">Highlighted div</div>
CSS
.highlight {
background-color: yellow;
font-weight: bold;
}
Result
┌─────────────────────────────────────────────────────────────┐
│ RENDERED OUTPUT │
└─────────────────────────────────────────────────────────────┘
Normal paragraph ← Not highlighted
Highlighted paragraph ← Yellow background, bold
Another highlighted paragraph ← Yellow background, bold
Highlighted div ← Yellow background, bold
Key Points
✓ Classes are REUSABLE (multiple elements can share one class)
✓ Elements can have MULTIPLE classes
✓ Classes work across different element types
✓ Use meaningful class names (highlight, button, card, etc.)
Multiple Classes
HTML:
<p class="highlight important">Very important text</p>
CSS:
.highlight {
background-color: yellow;
}
.important {
color: red;
font-weight: bold;
}
Result:
Very important text
↑ Yellow background (from .highlight)
↑ Red, bold text (from .important)
Visual: How Class Selectors Work
┌─────────────────────────────────────────────────────────────┐
│ CLASS SELECTOR TARGETING │
└─────────────────────────────────────────────────────────────┘
HTML:
<p>Normal</p>
<p class="special">Special paragraph</p>
<div>Normal div</div>
<div class="special">Special div</div>
CSS:
.special { color: green; }
Targets:
<p>Normal</p> ✗ (no class)
<p class="special">...</p> ✓ (has .special class)
<div>Normal div</div> ✗ (no class)
<div class="special">...</div> ✓ (has .special class)
Naming Conventions
✓ GOOD class names:
├── .button
├── .card
├── .highlight
├── .nav-menu
└── .user-profile
✗ BAD class names:
├── .red (describes appearance, not purpose)
├── .big (too vague)
├── .style1 (meaningless)
├── .asdf (no meaning)
└── .DIV (uppercase, confusing)
3. ID Selector
The ID selector targets ONE unique element with a specific ID.
Syntax
#idname {
/* styles */
}
Note the hash (#) prefix!
HTML Setup
<h1 id="main-title">My Website</h1>
<p id="intro">Introduction paragraph</p>
<p>Regular paragraph</p>
<p>Another regular paragraph</p>
CSS
#main-title {
color: darkblue;
font-size: 48px;
}
#intro {
font-style: italic;
color: gray;
}
Result
┌─────────────────────────────────────────────────────────────┐
│ RENDERED OUTPUT │
└─────────────────────────────────────────────────────────────┘
My Website ← Dark blue, 48px
(from #main-title)
Introduction paragraph ← Italic, gray
(from #intro)
Regular paragraph ← No special styling
Another regular paragraph ← No special styling
Key Points
✓ IDs must be UNIQUE (one per page)
✓ IDs are more SPECIFIC than classes
✓ Use for truly unique elements (header, main-content, footer)
✗ Don't reuse the same ID multiple times on one page
Class vs ID: When to Use What
┌─────────────────────────────────────────────────────────────┐
│ CLASS vs ID DECISION GUIDE │
└─────────────────────────────────────────────────────────────┘
Use CLASS when:
├── Style applies to MULTIPLE elements
├── Element might repeat (buttons, cards, list items)
└── General styling patterns
Example:
<button class="btn">Click</button>
<button class="btn">Submit</button>
<button class="btn">Cancel</button>
Use ID when:
├── Element is UNIQUE on the page
├── Only ONE instance exists
└── Need to target with JavaScript or anchors
Example:
<header id="main-header">...</header>
<main id="content">...</main>
<footer id="main-footer">...</footer>
Visual: How ID Selectors Work
┌─────────────────────────────────────────────────────────────┐
│ ID SELECTOR TARGETING │
└─────────────────────────────────────────────────────────────┘
HTML:
<h1 id="hero-title">Welcome</h1>
<p>Paragraph 1</p>
<p id="intro">Introduction</p>
<p>Paragraph 2</p>
CSS:
#intro { color: purple; }
Targets:
<h1 id="hero-title">Welcome</h1> ✗ (different ID)
<p>Paragraph 1</p> ✗ (no ID)
<p id="intro">Introduction</p> ✓ (matches #intro)
<p>Paragraph 2</p> ✗ (no ID)
4. Group Selectors
Group selectors let you apply the same styles to multiple selectors at once.
Syntax
selector1, selector2, selector3 {
/* styles */
}
Note the commas (,) separating selectors!
Example
Without grouping (repetitive):
h1 {
color: navy;
font-family: Arial;
}
h2 {
color: navy;
font-family: Arial;
}
h3 {
color: navy;
font-family: Arial;
}
With grouping (efficient):
h1, h2, h3 {
color: navy;
font-family: Arial;
}
Both produce the same result, but grouping is cleaner!
Complex Grouping
You can group any combination of selectors:
/* Group element, class, and ID selectors */
h1, .special, #intro {
text-align: center;
}
HTML:
<h1>Title</h1>
<p class="special">Special paragraph</p>
<div id="intro">Introduction</div>
<p>Regular paragraph</p>
Result:
All three elements (h1, .special, #intro) are centered
Regular paragraph remains left-aligned
Visual: How Group Selectors Work
┌─────────────────────────────────────────────────────────────┐
│ GROUP SELECTOR TARGETING │
└─────────────────────────────────────────────────────────────┘
CSS:
h1, p, .box { color: red; }
Equivalent to:
h1 { color: red; }
p { color: red; }
.box { color: red; }
HTML:
<h1>Title</h1> ✓ (red)
<p>Text</p> ✓ (red)
<div class="box">...</div> ✓ (red)
<span>Text</span> ✗ (not targeted)
When to Use
✓ Multiple elements need identical styles
✓ Reduce CSS repetition
✓ Keep code DRY (Don't Repeat Yourself)
Example use cases:
├── All headings same color
├── Multiple buttons same background
└── Several sections same padding
5. Descendant Selectors (Combinator)
Descendant selectors target elements that are INSIDE other elements.
Syntax
ancestor descendant {
/* styles */
}
Note the space between selectors!
Example
HTML:
<div class="container">
<p>Paragraph inside container</p>
<p>Another paragraph inside container</p>
</div>
<p>Paragraph outside container</p>
CSS:
.container p {
color: blue;
}
Result:
┌─────────────────────────────────────────────────────────────┐
│ RENDERED OUTPUT │
└─────────────────────────────────────────────────────────────┘
Paragraph inside container ← Blue (inside .container)
Another paragraph inside container ← Blue (inside .container)
Paragraph outside container ← Normal (NOT inside .container)
Deeper Nesting
Descendant selectors work at ANY depth:
HTML:
<div class="box">
<article>
<section>
<p>Deeply nested paragraph</p>
</section>
</article>
</div>
CSS:
.box p {
color: green;
}
Result:
The <p> is styled green even though it's 3 levels deep!
Multiple Levels
/* Target links inside list items inside nav */
nav li a {
text-decoration: none;
}
HTML:
<nav>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
</ul>
</nav>
<a href="#">Link outside nav</a>
Result:
Links inside <nav>: No underline
Link outside <nav>: Normal underline
Visual: How Descendant Selectors Work
┌─────────────────────────────────────────────────────────────┐
│ DESCENDANT SELECTOR TARGETING │
└─────────────────────────────────────────────────────────────┘
CSS:
div p { color: orange; }
HTML:
<div>
<p>Paragraph 1</p> ✓ (p inside div)
<section>
<p>Paragraph 2</p> ✓ (p inside div, any depth)
</section>
</div>
<p>Paragraph 3</p> ✗ (p NOT inside div)
Structure:
div
├── p ✓
└── section
└── p ✓
p ✗ (outside div)
When to Use
✓ Style elements only in specific contexts
✓ Override general styles in specific sections
✓ Create scoped styling
Example use cases:
├── Links in navigation vs links in content
├── Paragraphs in sidebar vs main content
└── Images in header vs images in footer
Selector Priority (Specificity) – High Level
When multiple CSS rules target the same element, specificity determines which rule wins.
The Hierarchy (Simplified)
┌─────────────────────────────────────────────────────────────┐
│ SELECTOR PRIORITY (LOWEST TO HIGHEST) │
└─────────────────────────────────────────────────────────────┘
1. Element selector (weakest)
p { color: blue; }
2. Class selector
.highlight { color: green; }
3. ID selector (strongest)
#intro { color: red; }
Example: Specificity in Action
HTML:
<p id="intro" class="highlight">What color am I?</p>
CSS:
p {
color: blue; /* Element selector */
}
.highlight {
color: green; /* Class selector */
}
#intro {
color: red; /* ID selector */
}
Result:
Text is RED
Why? ID selector (#intro) beats class (.highlight) beats element (p)
Visual: Specificity Hierarchy
┌─────────────────────────────────────────────────────────────┐
│ SPECIFICITY WEIGHT │
└─────────────────────────────────────────────────────────────┘
ID Selector (#)
██████████████████████ (Most specific - weight: 100)
Class Selector (.)
██████████ (Medium specific - weight: 10)
Element Selector
███ (Least specific - weight: 1)
When rules conflict, highest weight wins
Combining Selectors Increases Specificity
/* Low specificity */
p {
color: blue;
}
/* Medium specificity */
.container p {
color: green;
}
/* Higher specificity */
.container .highlight {
color: orange;
}
/* Highest specificity */
#intro {
color: red;
}
Rule of thumb:
More specific selector = Higher priority
Important Note for Beginners
Don't worry too much about specificity yet!
For now, remember:
├── IDs are strongest
├── Classes are medium
└── Elements are weakest
As you learn more CSS, specificity will become clearer.
Complete Example: Putting It All Together
Let's build a simple card component using different selectors:
HTML:
<div class="card">
<h2 id="card-title">Product Name</h2>
<p class="description">This is a product description.</p>
<p class="price">$29.99</p>
<button class="btn">Buy Now</button>
</div>
<p>Regular paragraph outside card</p>
<button>Regular button</button>
CSS:
/* Element selector - all cards get padding */
.card {
padding: 20px;
border: 1px solid gray;
background-color: white;
}
/* ID selector - unique title */
#card-title {
color: darkblue;
font-size: 24px;
}
/* Class selector - description styling */
.description {
color: #666;
font-size: 14px;
}
/* Class selector - price styling */
.price {
color: green;
font-weight: bold;
font-size: 20px;
}
/* Class selector - button styling */
.btn {
background-color: blue;
color: white;
padding: 10px 20px;
border: none;
}
/* Descendant selector - only paragraphs in card */
.card p {
margin: 10px 0;
}
/* Group selector - all headings */
h1, h2, h3 {
font-family: Arial, sans-serif;
}
Result:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Product Name ← #card-title (blue, 24px) │
│ │
│ This is a product ← .description (gray, 14px) │
│ description. │
│ │
│ $29.99 ← .price (green, bold, 20px) │
│ │
│ ┌──────────┐ │
│ │ Buy Now │ ← .btn (blue bg, white text) │
│ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Regular paragraph outside card ← No .card p styling
┌────────────┐
│ Button │ ← No .btn styling
└────────────┘
Selector Quick Reference
┌─────────────────────────────────────────────────────────────┐
│ CSS SELECTOR CHEAT SHEET │
└─────────────────────────────────────────────────────────────┘
BASIC SELECTORS
───────────────────────────────────────────────────────────────
Element Selector
p { } All <p> elements
Class Selector
.classname { } All elements with class="classname"
ID Selector
#idname { } Element with id="idname"
Group Selector
h1, h2, p { } All h1, h2, and p elements
Descendant Selector
div p { } All <p> inside <div> (any depth)
SPECIFICITY (Simple)
───────────────────────────────────────────────────────────────
Element < Class < ID
p { } Weakest
.box { } Medium
#header { } Strongest
Common Mistakes and How to Avoid Them
1. Forgetting the Dot for Classes
❌ WRONG:
highlight {
color: yellow;
}
✓ CORRECT:
.highlight {
color: yellow;
}
2. Forgetting the Hash for IDs
❌ WRONG:
intro {
font-size: 18px;
}
✓ CORRECT:
#intro {
font-size: 18px;
}
3. Using IDs Multiple Times
❌ WRONG:
<p id="special">Text 1</p>
<p id="special">Text 2</p>
✓ CORRECT:
<p class="special">Text 1</p>
<p class="special">Text 2</p>
4. Missing Space in Descendant Selector
❌ WRONG (this is a different selector!):
div.box {
/* Targets <div class="box">, not descendants */
}
✓ CORRECT (descendant selector):
div .box {
/* Targets .box inside <div> */
}
5. Overusing IDs
❌ AVOID:
#button1 { }
#button2 { }
#button3 { }
✓ BETTER:
.button { } /* Reusable class */
Practice Exercises
Try styling these HTML structures:
Exercise 1: Basic Selectors
HTML:
<h1>Main Title</h1>
<p class="intro">Introduction paragraph</p>
<p>Regular paragraph</p>
<p id="conclusion">Conclusion paragraph</p>
Task:
1. Make <h1> dark blue
2. Make .intro italic
3. Make #conclusion bold and green
4. Make all <p> elements have 16px font size
Exercise 2: Descendant Selectors
HTML:
<div class="box">
<h2>Box Title</h2>
<p>Text inside box</p>
</div>
<h2>Outside Title</h2>
<p>Text outside box</p>
Task:
1. Make paragraphs inside .box gray
2. Make headings inside .box blue
3. Leave outside elements unstyled
Exercise 3: Group Selectors
HTML:
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<p>Paragraph</p>
Task:
1. Make all headings (h1, h2, h3) the same font family
2. Make only h1 and h2 navy blue
3. Make p a different color
Summary: The Foundation of CSS
CSS selectors are the targeting system that makes styling possible.
┌─────────────────────────────────────────────────────────────┐
│ WHAT YOU LEARNED │
└─────────────────────────────────────────────────────────────┘
Element Selector
p { } Target all elements of a type
Class Selector
.classname { } Target elements by class (reusable)
ID Selector
#idname { } Target unique element by ID
Group Selector
h1, h2, p { } Target multiple selectors at once
Descendant Selector
div p { } Target nested elements
Specificity
ID > Class > Element Priority when rules conflict
Key Takeaways:
✓ Selectors tell CSS WHICH elements to style
✓ Element selectors target ALL of one type
✓ Classes are REUSABLE, IDs are UNIQUE
✓ Descendant selectors provide CONTEXT
✓ More specific selectors WIN conflicts
Master these basics before moving to advanced selectors (pseudo-classes, attribute selectors, etc.).
Selectors are the first step. Properties and values come next. But without selectors, you can't style anything at all! 🎯