CSS ยท Lesson 28

CSS Combinators ยท Targeting Elements by Their Relationships

8 phases  ยท  Build: Project Overview

๐Ÿ‘‹ Welcome to Lesson 28

So far you have learned to target HTML elements using simple selectors like p, .classname, and #id. But what if you only want to style a <p> that is inside a specific <div>? Or only the <p> that comes immediately after an <h2>? Or only the direct children of a sidebar?

This is exactly what CSS combinators solve. A combinator is a symbol you place between two selectors to describe a relationship between them. Instead of targeting every <p> on the page, you can target a <p> only when it appears in a specific place in your HTML structure.

In this lesson you will learn:

  • What a combinator is and why it exists
  • All four CSS combinators: descendant ( ), child (>), adjacent sibling (+), and general sibling (~)
  • How to read, write, and apply each combinator with working code examples
  • How to combine multiple combinators to write powerful, precise selectors
  • How to build a real-world styled article page using all four combinators together

By the end of this lesson, you will be able to write CSS selectors that are surgical ยท targeting exactly the right element in exactly the right context, without needing extra classes or IDs.


๐Ÿ“š 8 phases๐Ÿ—๏ธ Project Overview๐ŸŒ GitHub Pages
Phase 1 of 8
Lesson Introduction

So far you have learned to target HTML elements using simple selectors like p, .classname, and #id. But what if you only want to style a <p> that is inside a specific <div>? Or only the <p> that comes immediately after an <h2>? Or only the direct children of a sidebar?

This is exactly what CSS combinators solve. A combinator is a symbol you place between two selectors to describe a relationship between them. Instead of targeting every <p> on the page, you can target a <p> only when it appears in a specific place in your HTML structure.

In this lesson you will learn:

  • What a combinator is and why it exists
  • All four CSS combinators: descendant ( ), child (>), adjacent sibling (+), and general sibling (~)
  • How to read, write, and apply each combinator with working code examples
  • How to combine multiple combinators to write powerful, precise selectors
  • How to build a real-world styled article page using all four combinators together

By the end of this lesson, you will be able to write CSS selectors that are surgical ยท targeting exactly the right element in exactly the right context, without needing extra classes or IDs.


โœ๏ธ Your Task
Practise what you just learned about Lesson Introduction. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 2 of 8
Prerequisite Concepts

Before learning combinators, you need to understand two ideas: CSS selectors and the HTML family-tree structure.

1. What is a CSS Selector?

A CSS selector is the part of a CSS rule that identifies which HTML element(s) you want to style.

css
/* Selector โ†’ Style rule */
p {
  color: blue;
}

Here, p is the selector ยท it targets every <p> element on the page.

You already know simple selectors:

  • p ยท selects all paragraph elements
  • .highlight ยท selects all elements with class "highlight"
  • #header ยท selects the element with id "header"

But sometimes you need to target an element only when it has a specific relationship to another element.

2. The HTML Tree ยท Parents, Children, Descendants, and Siblings

HTML elements are nested inside each other, forming a structure like a family tree. Understanding this tree is the key to understanding combinators.

Consider this HTML:

html
<div>               โ† parent
  <p>First</p>      โ† child of div, sibling of Second and Third
  <p>Second</p>     โ† child of div, sibling of First and Third
  <span>
    <p>Third</p>    โ† child of span, grandchild of div (descendant)
  </span>
</div>
<p>Outside</p>      โ† NOT inside div at all

Vocabulary you need:

  • Parent ยท the element directly containing another element. In the example above, <div> is the parent of the first two <p> tags.
  • Child ยท an element directly inside a parent. The two <p> tags and the <span> are direct children of <div>.
  • Descendant ยท any element inside another element, no matter how deeply nested. The third <p> (inside <span> inside <div>) is a descendant of <div>, even though it is not a direct child.
  • Sibling ยท two elements that share the same parent. The two <p> tags inside <div> are siblings of each other.
  • Adjacent sibling ยท a sibling that comes immediately after another in the HTML code.

Analogy: Think of it like a real family. Your parent is one level above you. Your siblings share the same parent. Your descendants are your children, grandchildren, great-grandchildren, etc.


โœ๏ธ Your Task
Practise what you just learned about Prerequisite Concepts. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 3 of 8
Conceptual Understanding

What is a CSS Combinator?

A combinator is a special character placed between two selectors that tells the browser about the relationship required between those two elements for the style to apply.

css
/* General pattern */
selector1 COMBINATOR selector2 {
  /* styles apply to selector2 when it has the right relationship to selector1 */
}

There are four CSS combinators:

NameSymbolMeaning
Descendant (a space)Any matching element anywhere inside the first
Child>Only direct children of the first
Adjacent Sibling+Only the immediately following sibling
General Sibling~All following siblings

๐Ÿ’ก Key insight: Combinators do NOT style the first selector ยท they style the second selector, but only when the first selector's relationship condition is met. The first selector sets the context; the second is what actually gets styled.


โœ๏ธ Your Task
Practise what you just learned about Conceptual Understanding. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 4 of 8
The Four Combinators ยท Full Detailed Explanations

Combinator 1 ยท The Descendant Selector (space)

Symbol: A single space between two selectors: A B

What it does: Selects every element matching B that is located anywhere inside element A ยท whether it is a direct child, grandchild, great-grandchild, or even deeper.

Think of it like: "Give me all the <p> tags that live inside this <div>, no matter how deep they are buried."

Syntax:

css
ancestor descendant {
  /* styles */
}

Simple Example 1 ยท Descendant Selector

html
<!DOCTYPE html>
<html>
<head>
  <style>
    div p {
      background-color: yellow;
    }
  </style>
</head>
<body>

  <div>
    <p>Paragraph 1 โ€” inside div (styled โœ…)</p>
    <p>Paragraph 2 โ€” inside div (styled โœ…)</p>
    <section>
      <p>Paragraph 3 โ€” inside section inside div (styled โœ…)</p>
    </section>
  </div>

  <p>Paragraph 4 โ€” OUTSIDE div (NOT styled โŒ)</p>

</body>
</html>

Expected Output (visually):

code
[yellow background] Paragraph 1 โ€” inside div
[yellow background] Paragraph 2 โ€” inside div
[yellow background] Paragraph 3 โ€” inside section inside div
Paragraph 4 โ€” OUTSIDE div     โ† no yellow background

Breaking down the code:

div p ยท The space between div and p is the descendant combinator. It tells the browser: "Find all <p> elements that exist anywhere inside a <div>."

Notice that Paragraph 3 is inside <section> which is inside <div>. Even though there is an extra layer (section) between div and p, the descendant selector still finds it because it searches all levels down.

Paragraph 4 is outside the <div>, so it is NOT styled.

๐Ÿค” Thinking prompt: What if you added another <p> inside a <span> inside the <div>? Would it get styled? Yes! The descendant selector goes as deep as needed.


Combinator 2 ยท The Child Selector (>)

Symbol: > (greater-than sign): A > B

What it does: Selects only elements matching B that are direct children of A. Grandchildren and deeper descendants are NOT selected.

Think of it like: "Only style my immediate children ยท not my grandchildren."

Syntax:

css
parent > direct-child {
  /* styles */
}

Simple Example 2 ยท Child Selector

html
<!DOCTYPE html>
<html>
<head>
  <style>
    div > p {
      background-color: lightblue;
    }
  </style>
</head>
<body>

  <div>
    <p>Paragraph 1 โ€” direct child of div (styled โœ…)</p>
    <p>Paragraph 2 โ€” direct child of div (styled โœ…)</p>
    <section>
      <p>Paragraph 3 โ€” child of section, NOT direct child of div (NOT styled โŒ)</p>
    </section>
  </div>

  <p>Paragraph 4 โ€” outside div (NOT styled โŒ)</p>

</body>
</html>

Expected Output (visually):

code
[light blue] Paragraph 1 โ€” direct child of div
[light blue] Paragraph 2 โ€” direct child of div
Paragraph 3 โ€” child of section, NOT direct child of div     โ† no styling
Paragraph 4 โ€” outside div                                   โ† no styling

Breaking down the code:

div > p ยท The > means "direct child only." Paragraphs 1 and 2 are direct children of <div>, so they are styled. Paragraph 3 is a direct child of <section>, not of <div> ยท so it is not styled by this rule.

Descendant vs. Child ยท The Key Difference:

SelectorSelects Paragraph 3 inside <section> inside <div>?
div p (descendant)โœ… Yes ยท selects all levels deep
div > p (child)โŒ No ยท only direct children

๐Ÿค” Thinking prompt: When would you want to use > instead of (space)? Use > when you have nested structures and only want to style one specific level ยท for example, styling only the top-level menu items in a nav bar, but not items inside sub-menus.


Combinator 3 ยท The Adjacent Sibling Selector (+)

Symbol: + (plus sign): A + B

What it does: Selects the single element matching B that comes immediately after element A, AND both must share the same parent.

Think of it like: "Style only my next-door neighbour ยท the one who comes right after me."

Key rules:

  • Both A and B must share the same parent
  • B must appear directly after A in the HTML ยท no other elements between them
  • Only one element is selected (the immediate next sibling), not multiple

Syntax:

css
element + immediately-following-sibling {
  /* styles */
}

Simple Example 3 ยท Adjacent Sibling Selector

html
<!DOCTYPE html>
<html>
<head>
  <style>
    h2 + p {
      background-color: lightgreen;
    }
  </style>
</head>
<body>

  <h2>A Heading</h2>
  <p>This paragraph is right after h2 (styled โœ…)</p>
  <p>This paragraph is NOT right after h2 (NOT styled โŒ)</p>

  <h2>Another Heading</h2>
  <p>This paragraph is right after h2 again (styled โœ…)</p>
  <p>This one is not right after h2 (NOT styled โŒ)</p>

</body>
</html>

Expected Output (visually):

code
A Heading
[light green] This paragraph is right after h2
This paragraph is NOT right after h2

Another Heading
[light green] This paragraph is right after h2 again
This one is not right after h2

Breaking down the code:

h2 + p ยท "Find a <p> that comes immediately after an <h2>."

The first <p> after each <h2> is styled. The second, third, or any further <p> after the heading is not styled ยท only the immediately adjacent one.

๐ŸŒ Real-World Use: This pattern is extremely common for styling the paragraph that follows a section heading differently ยท for example, making the first paragraph after a heading slightly larger (a "lead paragraph" or "drop cap" effect).

Second Example ยท What Happens When Another Element Is Between Them?

html
<!DOCTYPE html>
<html>
<head>
  <style>
    h2 + p {
      color: red;
    }
  </style>
</head>
<body>

  <h2>Heading</h2>
  <span>I am between the h2 and the p!</span>
  <p>This p is NOT right after h2 โ€” a span is in the way (NOT styled โŒ)</p>

</body>
</html>

Expected Output:

code
Heading
I am between the h2 and the p!
This p is NOT right after h2 โ€” a span is in the way    โ† NOT red

Because the <span> is between the <h2> and the <p>, the <p> is no longer the immediate sibling of <h2>. The + combinator is not applied.

๐Ÿ’ก Important: The + combinator is very strict ยท there must be zero other elements between A and B. Even a single <br> or <span> in between will break the match.


Combinator 4 ยท The General Sibling Selector (~)

Symbol: ~ (tilde): A ~ B

What it does: Selects all elements matching B that come after element A, as long as they share the same parent. They do not need to be immediately adjacent ยท there can be other elements between them.

Think of it like: "Style all of my younger siblings ยท not just the one right next to me, but all of them who come after me."

Key differences from +:

  • + selects only the one immediately following sibling
  • ~ selects all following siblings that match

Syntax:

css
element ~ all-following-siblings {
  /* styles */
}

Simple Example 4 ยท General Sibling Selector

html
<!DOCTYPE html>
<html>
<head>
  <style>
    h2 ~ p {
      background-color: lightyellow;
    }
  </style>
</head>
<body>

  <p>This p comes BEFORE h2 (NOT styled โŒ)</p>

  <h2>The Heading</h2>

  <p>Paragraph 1 after h2 (styled โœ…)</p>
  <p>Paragraph 2 after h2 (styled โœ…)</p>
  <span>I am a span โ€” not a p, so not styled</span>
  <p>Paragraph 3 after h2 (still styled โœ…)</p>

</body>
</html>

Expected Output (visually):

code
This p comes BEFORE h2                   โ† NOT styled

The Heading

[light yellow] Paragraph 1 after h2
[light yellow] Paragraph 2 after h2
I am a span โ€” not a p, so not styled
[light yellow] Paragraph 3 after h2

Breaking down the code:

h2 ~ p ยท "Find all <p> elements that come after an <h2>, anywhere after it, as long as they share the same parent."

Notice:

  • The <p> before the <h2> is NOT styled ยท the ~ combinator only looks forward, never backward.
  • The <span> is ignored ยท it is not a <p> so the selector doesn't match it.
  • The third <p> after the <span> is still styled ยท unlike +, the ~ selector doesn't care about other elements in between, as long as the <p> comes after the <h2>.

โœ๏ธ Your Task
Practise what you just learned about The Four Combinators ยท Full Detailed Explanations. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 5 of 8
All Four Combinators ยท Visual Summary

Here is a diagram to show the structure and what each combinator selects:

code
HTML Structure:
<div>
  <p>A</p>          โ† direct child of div
  <section>
    <p>B</p>        โ† grandchild of div, child of section
  </section>
  <p>C</p>          โ† direct child of div
  <p>D</p>          โ† direct child of div
</div>
<p>E</p>            โ† outside div entirely
SelectorWhat gets styled
div p (descendant)A, B, C, D ยท all p's inside div at any depth
div > p (child)A, C, D ยท only direct children of div
section + pC ยท the p immediately after section
section ~ pC, D ยท all p's that come after section

โœ๏ธ Your Task
Practise what you just learned about All Four Combinators ยท Visual Summary. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 6 of 8
Simple Standalone Examples (Second Set)

Example 5 ยท Descendant Selector in a Navigation Menu

html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* Style ALL links that are anywhere inside the nav element */
    nav a {
      color: white;
      text-decoration: none;
      font-weight: bold;
    }

    nav {
      background-color: #333;
      padding: 10px;
    }
  </style>
</head>
<body>

  <nav>
    <a href="#">Home</a>
    <div>
      <a href="#">Products</a>   <!-- nested inside a div, but still inside nav -->
      <a href="#">Services</a>
    </div>
  </nav>

  <a href="#">This link is outside nav โ€” not styled</a>

</body>
</html>

Expected Output:

code
[dark bar with white bold links] Home  Products  Services

This link is outside nav โ€” not styled   โ† default blue underlined link

The nav a selector styles ALL anchor tags anywhere inside <nav>, regardless of whether they are direct children or inside nested <div> elements.


Example 6 ยท Child Selector for a List Menu (Avoids Deep Nesting)

html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* Style only DIRECT children of ul.menu โ€” not nested sub-menu items */
    ul.menu > li {
      list-style-type: none;
      display: inline-block;
      padding: 10px 20px;
      background-color: #4a90d9;
      color: white;
      margin: 2px;
    }
  </style>
</head>
<body>

  <ul class="menu">
    <li>Home</li>
    <li>About
      <ul>
        <li>Team</li>      <!-- NOT styled โ€” this is a child of inner ul, not menu -->
        <li>History</li>   <!-- NOT styled -->
      </ul>
    </li>
    <li>Contact</li>
  </ul>

</body>
</html>

Expected Output (visually):

code
[blue box: Home]  [blue box: About]  [blue box: Contact]
                     Team               โ† plain text, no blue box
                     History            โ† plain text, no blue box

Using ul.menu > li instead of ul.menu li (descendant) means only the top-level list items get the blue button styling ยท the nested sub-menu items are left unstyled.

๐ŸŒ Real-World Connection: This exact pattern ยท nav ul > li ยท is used in almost every multi-level navigation menu on the web to style top-level items differently from sub-menu items.


Example 7 ยท Adjacent Sibling for a Lead Paragraph

html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* Style only the first paragraph after each section heading */
    h2 + p {
      font-size: 18px;
      font-style: italic;
      color: #555;
    }

    p {
      font-size: 14px;
      color: #333;
    }
  </style>
</head>
<body>

  <h2>Introduction</h2>
  <p>This is the lead paragraph โ€” larger and italic.</p>
  <p>This is a regular paragraph โ€” smaller and normal.</p>
  <p>Another regular paragraph.</p>

  <h2>Chapter One</h2>
  <p>This is the lead paragraph for Chapter One โ€” larger and italic.</p>
  <p>Back to regular size.</p>

</body>
</html>

Expected Output:

code
Introduction
  [18px italic grey] This is the lead paragraph โ€” larger and italic.
  [14px normal] This is a regular paragraph โ€” smaller and normal.
  [14px normal] Another regular paragraph.

Chapter One
  [18px italic grey] This is the lead paragraph for Chapter One โ€” larger and italic.
  [14px normal] Back to regular size.

The h2 + p rule fires once per heading ยท only the paragraph immediately following the <h2> gets the special treatment.


Example 8 ยท General Sibling for a "Selected" State Effect

html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* When a radio button is selected, style all p siblings after it */
    input[type="radio"]:checked ~ p {
      color: green;
      font-weight: bold;
    }
  </style>
</head>
<body>

  <input type="radio" name="demo" id="on">
  <label for="on">Toggle on</label>

  <p>This paragraph changes when the radio is checked!</p>
  <p>So does this one!</p>

</body>
</html>

Expected Output:

  • Before clicking: both paragraphs appear in normal black text.
  • After clicking the radio button: both paragraphs turn green and bold.

This uses the ~ combinator with :checked pseudo-class to create a CSS-only toggle effect ยท no JavaScript needed!


โœ๏ธ Your Task
Practise what you just learned about Simple Standalone Examples (Second Set). Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 7 of 8
Guided Practice Exercises
๐ŸŽฏ Your Challenge

Exercise 1 ยท Warm-Up: Descendant vs. Child

Objective: Understand the visual difference between descendant and child combinators.

Scenario: You are building a content page with a main article and a sidebar. You want to colour the paragraphs in the article but NOT the paragraphs in the sidebar.

โœ๏ธ Task
Practise what you just learned about Guided Practice Exercises. Open your editor, type the examples above by hand, modify them, and observe what changes.
html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* YOUR TASK: Write a selector here that colours ONLY the
       paragraphs inside #article, NOT those inside #sidebar */

    #article p {
      color: darkblue;
    }
  </style>
</head>
<body>

  <div id="article">
    <p>Article paragraph 1</p>
    <p>Article paragraph 2</p>
    <div class="pull-quote">
      <p>Quoted text inside article</p>
    </div>
  </div>

  <div id="sidebar">
    <p>Sidebar paragraph โ€” should NOT be blue</p>
  </div>

</body>
</html>

Expected Output:

code
[dark blue] Article paragraph 1
[dark blue] Article paragraph 2
[dark blue] Quoted text inside article   โ† styled because it's a DESCENDANT of #article
Sidebar paragraph โ€” should NOT be blue   โ† normal black text

Self-check Questions:

  1. The "Quoted text inside article" is inside a <div class="pull-quote"> which is inside #article. Is it styled? Why?
  2. What would you change to make #article > p instead? Which paragraph would then NOT be styled?
  3. Try it: change #article p to #article > p. What changes?

Exercise 2 ยท Building a Table of Contents with Sibling Selectors

Objective: Use sibling selectors to style headings and the content that follows them.

Scenario: You are formatting a recipe page. Each recipe section has an <h3> title followed by several elements. You want to:

  • Make the first paragraph after each <h3> (the description) appear in italic
  • Make ALL paragraphs after each <h3> have a slightly indented left margin

Starter Code:

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      font-family: Georgia, serif;
      max-width: 600px;
      margin: 30px auto;
    }

    /* Adjacent sibling: first p right after h3 โ€” the recipe description */
    h3 + p {
      font-style: italic;
      color: #666;
    }

    /* General sibling: ALL p after h3 โ€” indent them all */
    h3 ~ p {
      margin-left: 20px;
    }
  </style>
</head>
<body>

  <h3>Jollof Rice</h3>
  <p>A rich, smoky one-pot rice dish loved across West Africa.</p>
  <p>Prep time: 20 minutes. Cook time: 45 minutes. Serves: 6.</p>
  <p>Pairs well with fried plantain and grilled chicken.</p>

  <h3>Egusi Soup</h3>
  <p>A hearty melon seed soup with leafy greens and meat or fish.</p>
  <p>Prep time: 30 minutes. Cook time: 1 hour. Serves: 8.</p>

</body>
</html>

Expected Output:

code
Jollof Rice
  [italic grey indented] A rich, smoky one-pot rice dish loved across West Africa.
  [indented] Prep time: 20 minutes. Cook time: 45 minutes. Serves: 6.
  [indented] Pairs well with fried plantain and grilled chicken.

Egusi Soup
  [italic grey indented] A hearty melon seed soup with leafy greens and meat or fish.
  [indented] Prep time: 30 minutes. Cook time: 1 hour. Serves: 8.

Note: The first paragraph after each <h3> gets BOTH the h3 + p style (italic, grey) AND the h3 ~ p style (margin-left). This is because it matches both selectors ยท CSS applies them both!

Self-check Questions:

  1. Why does the first paragraph get both font-style: italic and margin-left: 20px?
  2. Do the second and third paragraphs get font-style: italic? Why or why not?
  3. If you added a <hr> line between the <h3> and the first <p>, would the h3 + p rule still match? Why or why not?

Exercise 3 ยท Navigation Menu with Child Combinator

Objective: Build a two-level navigation menu where only the top-level items are styled as tab buttons.

html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* Reset */
    * { box-sizing: border-box; margin: 0; padding: 0; }

    .navbar {
      background-color: #2c3e50;
    }

    /* Style ONLY direct children of .navbar > ul โ€” the top-level items */
    .navbar > ul > li {
      display: inline-block;
      padding: 14px 20px;
      color: white;
      font-family: Arial, sans-serif;
      font-size: 15px;
      cursor: pointer;
      position: relative;
    }

    .navbar > ul > li:hover {
      background-color: #e74c3c;
    }

    /* Sub-menu styling โ€” nested uls */
    .navbar ul {
      list-style: none;
    }

    .navbar > ul > li > ul {
      display: none;
      position: absolute;
      background-color: #34495e;
      top: 100%;
      left: 0;
      min-width: 150px;
    }

    .navbar > ul > li:hover > ul {
      display: block;
    }

    .navbar > ul > li > ul > li {
      display: block;
      padding: 10px 15px;
      color: #ccc;
      font-size: 14px;
    }

    .navbar > ul > li > ul > li:hover {
      background-color: #e74c3c;
      color: white;
    }
  </style>
</head>
<body>

  <nav class="navbar">
    <ul>
      <li>Home</li>
      <li>Products
        <ul>
          <li>Laptops</li>
          <li>Tablets</li>
          <li>Phones</li>
        </ul>
      </li>
      <li>About</li>
      <li>Contact</li>
    </ul>
  </nav>

  <p style="padding: 20px;">Hover over "Products" to see the sub-menu.</p>

</body>
</html>

Expected Output:

code
[dark bar] Home  Products  About  Contact

(On hover over Products, a dropdown appears:)
  Laptops
  Tablets
  Phones

Self-check Questions:

  1. Why do we use .navbar > ul > li instead of .navbar li? What would break if we used the descendant combinator instead?
  2. What does position: relative on the parent <li> and position: absolute on the sub-menu <ul> achieve?
  3. Can you add another top-level item called "Blog" with two sub-items: "News" and "Tutorials"?

Phase 8 of 8
Common Beginner Mistakes

Mistake 1 ยท Confusing Descendant (space) with Child (>)

css
/* WRONG intent: want to style only direct children */
div p {    /* โ† This styles ALL p descendants, not just direct children */
  color: red;
}

/* CORRECT: use > for direct children only */
div > p {
  color: red;
}

When this bites you: You style a nav bar's top-level items, but the nested sub-menu items also get the same style unexpectedly.


Mistake 2 ยท Expecting + to Match When There Is an Element In Between

html
<h2>Title</h2>
<span>Some note</span>   <!-- โ† This breaks the adjacency! -->
<p>Lead paragraph</p>   <!-- h2 + p will NOT match this -->
css
/* This will NOT work because span is between h2 and p */
h2 + p {
  font-style: italic;
}

Fix: Either remove the element in between, or use h2 ~ p if you don't need strict adjacency.


Mistake 3 ยท Expecting ~ to Work Backwards

html
<p>This comes BEFORE h2</p>
<h2>Heading</h2>
<p>This comes AFTER h2</p>
css
/* h2 ~ p only styles p that come AFTER h2, never before */
h2 ~ p {
  color: green;
}
/* Result: only the SECOND <p> is green โ€” the first <p> is NOT affected */

Why this happens: All sibling combinators (+ and ~) only look forward in the document ยท they never look backward.


Mistake 4 ยท Confusing + (one sibling) with ~ (all siblings)

css
/* Styles only the FIRST p after h2 */
h2 + p { font-size: 20px; }

/* Styles ALL p elements after h2 */
h2 ~ p { font-size: 20px; }

Beginners often write h2 + p when they mean "all paragraphs after a heading." If you want all of them, use ~.


Mistake 5 ยท Forgetting That Combinators Style the SECOND Element

css
/* This does NOT change the div โ€” it changes the p */
div p {
  color: red;
}

The div is used to set the context (the p must be inside a div). The div itself is not styled by this rule. Only the <p> gets color: red.


Mistake 6 ยท Writing Extra Spaces Where They Change Meaning

css
div>p { ... }    /* Valid โ€” same as div > p */
div > p { ... }  /* Valid โ€” spaces around > are optional */
divp { ... }     /* INVALID โ€” this reads as a selector for <divp> element! */

Always make sure there is either a proper combinator symbol (>, +, ~) or a clear space between selectors. No space and no symbol means the browser treats it as one single selector name.


โœ๏ธ Your Task
Practise what you just learned about Common Beginner Mistakes. Open your editor, type the examples above by hand, modify them, and observe what changes.
๐Ÿ—๏ธ Build It โ€” Mini Project
Project Overview

In this project, you will style a complete news article page using all four CSS combinators in a meaningful, practical way.

Project Overview

You are building the article detail page for a fictional online magazine called "The Codebreaker". The article page needs:

  • Body text paragraphs styled in dark grey
  • The first paragraph after each section heading styled as a "lead paragraph" (larger, italic)
  • All paragraphs following section headings indented
  • Navigation links styled using descendant combinator
  • Section headings and their direct content styled differently from the main body

Stage 1 ยท HTML Structure

starter.html
<!DOCTYPE html>
<html>
<head>
  <title>The Codebreaker โ€” Article</title>
  <link rel="stylesheet" href="article.css">
</head>
<body>

  <!-- Navigation using descendant combinator -->
  <nav id="top-nav">
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">Tech</a></li>
      <li><a href="#">Science</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>

  <!-- Article content using all combinators -->
  <article id="main-article">

    <h1>How CSS Changed the Web Forever</h1>
    <p class="meta">Published by Ada Okafor ยท April 2026</p>

    <h2>The Beginning</h2>
    <p>Before CSS, all styling was done inline or with HTML attributes. Pages were messy, hard to maintain, and looked identical everywhere.</p>
    <p>CSS was introduced to separate structure from presentation, making web development cleaner and more powerful.</p>
    <p>Today, CSS is used by millions of developers worldwide to build beautiful, responsive interfaces.</p>

    <h2>The Revolution</h2>
    <p>When CSS2 arrived, developers gained new tools for layout, positioning, and more expressive typography.</p>
    <p>It allowed a single stylesheet to control the appearance of hundreds of pages simultaneously.</p>

    <h2>What Comes Next</h2>
    <p>CSS continues to evolve with features like Grid, Flexbox, custom properties, and container queries.</p>
    <p>The future is bright for web designers and developers who invest time in mastering this language.</p>

  </article>

  <!-- Sidebar using child combinator -->
  <aside id="sidebar">
    <h3>Related Articles</h3>
    <ul>
      <li><a href="#">Understanding Flexbox</a></li>
      <li><a href="#">CSS Grid Complete Guide</a></li>
      <li><a href="#">The History of HTML</a></li>
    </ul>
  </aside>

</body>
</html>

Lesson 28 complete! ๐ŸŽ‰

You covered: