CSS · Lesson 21

CSS Position · Static, Relative, Fixed, Absolute, and Sticky

12 phases  ·  Build: Project Overview

👋 Welcome to Lesson 21

Up until now, every element you have placed on a page has followed the same rule: elements stack from top to bottom, one after the other, in the order you wrote them in the HTML. This is called the normal document flow.

But look at any real website and you will immediately see elements that break this rule. A navigation bar that stays at the top of the screen even when you scroll. A tooltip that hovers just above a button. A banner image with a text label pinned to its bottom-left corner. A sidebar that scrolls with you until it reaches the top, then locks in place.

All of this is achieved with a single CSS property: position.

The position property is one of the most powerful and most misunderstood concepts in CSS. When you truly understand it, you gain the ability to place any element anywhere on the page · and keep it there through scrolling, resizing, and user interaction.

This lesson covers all five position values · static, relative, fixed, absolute, and sticky · fully and from scratch, progressively building toward a real-world project you can use immediately.


📚 12 phases🏗️ Project Overview🌐 GitHub Pages
Phase 1 of 12
Lesson Introduction

Up until now, every element you have placed on a page has followed the same rule: elements stack from top to bottom, one after the other, in the order you wrote them in the HTML. This is called the normal document flow.

But look at any real website and you will immediately see elements that break this rule. A navigation bar that stays at the top of the screen even when you scroll. A tooltip that hovers just above a button. A banner image with a text label pinned to its bottom-left corner. A sidebar that scrolls with you until it reaches the top, then locks in place.

All of this is achieved with a single CSS property: position.

The position property is one of the most powerful and most misunderstood concepts in CSS. When you truly understand it, you gain the ability to place any element anywhere on the page · and keep it there through scrolling, resizing, and user interaction.

This lesson covers all five position values · static, relative, fixed, absolute, and sticky · fully and from scratch, progressively building toward a real-world project you can use immediately.


✏️ 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 12
Prerequisite Concepts

What is the Normal Document Flow?

When a browser renders a page, it places every element in sequence, from top to bottom, following the HTML order. Block elements like <div>, <p>, <h1> take up the full width and stack vertically. Inline elements like <span>, <a> sit side by side in a line.

This default stacking is called the normal document flow or normal flow.

html
<div>Box One</div>
<div>Box Two</div>
<div>Box Three</div>

Expected output in browser:

code
┌──────────────────────┐
│ Box One              │
└──────────────────────┘
┌──────────────────────┐
│ Box Two              │
└──────────────────────┘
┌──────────────────────┐
│ Box Three            │
└──────────────────────┘

They stack vertically because that is normal flow.

What are the Offset Properties?

When you take an element out of normal flow and position it, you control its location using four offset properties:

PropertyMeaning
topDistance from the top edge of the reference point
bottomDistance from the bottom edge of the reference point
leftDistance from the left edge of the reference point
rightDistance from the right edge of the reference point

These properties do nothing unless position is set to something other than static. They always work together with the position property.

Important: The "reference point" changes depending on which position value you use. This is the key concept to understand in this lesson.


✏️ 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 12
Part 1 · `position: static` (The Default)

What is position: static?

Every HTML element has position: static by default. It means the element follows normal document flow and is not positioned by offset properties.

You almost never write position: static yourself. It is the starting state of every element unless you change it.

css
div {
  position: static;   /* This is the default — no change */
  top: 50px;          /* This does NOTHING when position is static */
  left: 50px;         /* This also does NOTHING */
}

Expected output: The top and left values are completely ignored. The element sits exactly where it would in normal flow.

Key rule: Offset properties (top, bottom, left, right) only work when position is relative, absolute, fixed, or sticky. They are ignored on static elements.

Example · static in action:

html
<!DOCTYPE html>
<html>
<head>
  <style>
    div.static-box {
      position: static;
      background-color: lightblue;
      padding: 20px;
      width: 200px;
    }
  </style>
</head>
<body>
  <div class="static-box">I am static (default)</div>
  <div class="static-box">I follow normal flow</div>
</body>
</html>

Expected output: Two light blue boxes stacked vertically, exactly as they appear in the HTML · no special positioning applied.


✏️ Your Task
Practise what you just learned about position: static (The Default). Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 4 of 12
Part 2 · `position: relative`

What is position: relative?

position: relative means the element is positioned relative to where it would normally be in the document flow.

Think of it this way: the element is placed in the page as normal, and then you can nudge it from that original position using offset properties. The original space it occupied remains reserved · no other element fills in the gap.

Analogy: Imagine you are standing in a queue. position: relative means you can lean forward or sideways, but your spot in the queue is still reserved for you. Nobody moves in to take your place.

Syntax

css
div.moved {
  position: relative;
  top: 20px;    /* Move DOWN 20px from its normal position */
  left: 40px;   /* Move RIGHT 40px from its normal position */
}

Confusing but important: top: 20px pushes the element DOWN (away from the top). left: 40px pushes the element RIGHT (away from the left). Think of the offset as the amount of space pushed in from that edge.

Simple Example

html
<!DOCTYPE html>
<html>
<head>
  <style>
    div {
      width: 180px;
      padding: 16px;
      font-family: Arial, sans-serif;
    }

    div.normal {
      background-color: #cfe2ff;
    }

    div.shifted {
      position: relative;
      top: 20px;
      left: 40px;
      background-color: #ffcdd2;
    }

    div.after {
      background-color: #c8e6c9;
    }
  </style>
</head>
<body>
  <div class="normal">Box 1 (normal)</div>
  <div class="shifted">Box 2 (relative — shifted 20px down, 40px right)</div>
  <div class="after">Box 3 (normal — notice it does NOT move up)</div>
</body>
</html>

Expected output:

  • Box 1: sits in normal flow
  • Box 2: visually shifted · it appears 20px lower and 40px to the right compared to where it would normally be. But the gap where it would have been is still there. Box 3 does not move up to fill the gap.
  • Box 3: sits right where it always would · it does not know Box 2 moved.

Thinking prompt: What happens if you change top: 20px to top: -20px? The element moves UP · because negative values reverse direction.

Using Negative Offsets

css
div.up-and-left {
  position: relative;
  top: -10px;    /* Moves 10px UPWARD */
  left: -20px;   /* Moves 20px to the LEFT */
}

Negative values pull the element in the opposite direction from the named edge.

Why position: relative Matters Beyond Moving

position: relative has a second very important purpose: it creates a positioning context for child elements with position: absolute. You will see this in Part 4. This is often the main reason developers use relative · not to move the element at all, but purely to set up a container that absolute children can be placed inside.


✏️ Your Task
Practise what you just learned about position: relative. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 5 of 12
Part 3 · `position: fixed`

What is position: fixed?

position: fixed takes the element completely out of the normal document flow and fixes it to a position relative to the browser viewport (the visible window area). It stays in that exact spot even when the user scrolls.

Analogy: Imagine a sticky note on your screen. No matter how much you scroll the document behind it, the sticky note never moves. That is position: fixed.

The reference point for fixed is always the viewport · the browser window itself.

Syntax

css
div.fixed-navbar {
  position: fixed;
  top: 0;       /* Pinned to the very top of the viewport */
  left: 0;      /* Pinned to the very left edge */
  width: 100%;  /* Stretches across the full width of the viewport */
}

Simple Example · Fixed Top Navigation Bar

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      font-family: Arial, sans-serif;
    }

    nav.fixed-nav {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      background-color: #1a237e;
      color: white;
      padding: 16px 24px;
      z-index: 1000;   /* Ensures it sits on top of other content */
    }

    main {
      margin-top: 60px;  /* Prevents content hiding under the fixed nav */
      padding: 20px;
    }

    p {
      margin-bottom: 20px;
    }
  </style>
</head>
<body>

  <nav class="fixed-nav">My Fixed Navigation Bar</nav>

  <main>
    <p>Scroll down to see the navigation bar stay fixed at the top.</p>
    <p>Paragraph 2. Keep scrolling.</p>
    <p>Paragraph 3. The nav doesn't move!</p>
    <p>Paragraph 4.</p>
    <p>Paragraph 5.</p>
    <p>Paragraph 6.</p>
    <p>Paragraph 7.</p>
    <p>Paragraph 8.</p>
  </main>

</body>
</html>

Line by line · new properties:

  • position: fixed · removes the nav from normal flow and locks it to the viewport
  • top: 0; left: 0; · pins it to the top-left corner of the window
  • width: 100%; · stretches across the full browser width
  • z-index: 1000; · ensures it renders on top of all other content when things overlap. We cover z-index in a later lesson; for now, just know that higher numbers sit on top.
  • margin-top: 60px; on <main> · because fixed elements are removed from flow, the main content would slide up underneath the nav. We push it down 60px (the height of the nav) to prevent overlap.

Expected output: A dark navy bar stays pinned at the top of the viewport while all the paragraphs scroll behind it.

Thinking prompt: What would happen if you removed margin-top: 60px from <main>? The first paragraph would be hidden behind the nav bar. This is a very common beginner mistake.

Fixed Bottom · A Cookie Banner / Footer Bar

css
div.cookie-banner {
  position: fixed;
  bottom: 0;      /* Pinned to the bottom of the viewport */
  left: 0;
  width: 100%;
  background-color: #333;
  color: white;
  padding: 14px 24px;
  text-align: center;
}

Expected output: A dark bar locked to the bottom of the browser window · exactly like a cookie consent banner.

Fixed Corner Button · "Back to Top"

css
a.back-to-top {
  position: fixed;
  bottom: 30px;     /* 30px from the bottom of the viewport */
  right: 30px;      /* 30px from the right edge of the viewport */
  background-color: #e94560;
  color: white;
  padding: 12px 16px;
  border-radius: 50%;
  text-decoration: none;
  font-size: 18px;
}

Expected output: A circular button pinned to the bottom-right corner of the screen · a pattern seen on nearly every long-scrolling website.


✏️ Your Task
Practise what you just learned about position: fixed. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 6 of 12
Part 4 · `position: absolute`

What is position: absolute?

position: absolute is where CSS positioning becomes truly powerful · and truly confusing if you do not understand the key rule.

position: absolute takes the element completely out of normal flow (like fixed) and positions it relative to its nearest positioned ancestor.

What is a "positioned ancestor"? An ancestor element (any parent, grandparent, or great-grandparent in the HTML tree) that has a position value other than static. This means relative, absolute, fixed, or sticky.

If no positioned ancestor exists, the element is positioned relative to the initial containing block · which is effectively the <html> element (the entire page).

The golden rule of position: absolute: "Absolute elements look UP the HTML tree to find their nearest non-static positioned ancestor. That ancestor becomes their reference box."

Analogy: Imagine you are inside a framed picture on a wall. You can move anywhere inside the frame. But if there is no frame, you can move anywhere on the entire wall. The frame is the "positioned ancestor." position: relative on a parent creates that frame.

Simple Example · No Positioned Ancestor

When no parent has position: relative (or any non-static position), the absolute element positions itself relative to the whole page:

html
<!DOCTYPE html>
<html>
<head>
  <style>
    div.absolute-box {
      position: absolute;
      top: 80px;
      right: 20px;
      background-color: #ffcdd2;
      padding: 16px;
      width: 180px;
    }
  </style>
</head>
<body>
  <p>This paragraph is in normal flow.</p>
  <div class="absolute-box">I am absolutely positioned from the page edge</div>
  <p>This paragraph also ignores the absolute box — they do not interact.</p>
</body>
</html>

Expected output: The red box appears 80px from the top and 20px from the right edge of the entire page. The paragraphs flow normally beneath it, completely unaware the box exists in flow (because it has been removed from it).


The Most Important Pattern · relative Parent + absolute Child

This is the most commonly used positioning pattern in all of web development. You set position: relative on a parent container (often with no offsets · just the keyword), and then place position: absolute children inside it, using offsets that are measured from the parent's edges.

html
<!DOCTYPE html>
<html>
<head>
  <style>
    div.card {
      position: relative;    /* Creates the positioning context */
      width: 300px;
      height: 200px;
      background-color: #e3f2fd;
      border: 1px solid #90caf9;
      border-radius: 8px;
    }

    div.badge {
      position: absolute;    /* Positions relative to .card */
      top: 10px;             /* 10px from the TOP of .card */
      right: 10px;           /* 10px from the RIGHT of .card */
      background-color: #e53935;
      color: white;
      padding: 4px 10px;
      border-radius: 20px;
      font-size: 12px;
      font-weight: bold;
      font-family: Arial, sans-serif;
    }
  </style>
</head>
<body>

  <div class="card">
    <div class="badge">NEW</div>
    <p style="padding: 16px;">A product card with a badge pinned to the top-right corner.</p>
  </div>

</body>
</html>

Expected output: A blue card with a small red "NEW" badge locked to the top-right corner inside the card · no matter how wide or narrow the viewport is, the badge stays pinned to the card's corner.

Why relative on .card with no offsets? Writing position: relative without top/left/right/bottom does not move the element at all. It only establishes a positioning context for absolute children. This is intentional and very common.

More Absolute Use Cases

Centred Overlay Text on an Image

html
<div class="image-container">
  <img src="photo.jpg" alt="City" width="400" height="250">
  <div class="overlay-text">Paris, France</div>
</div>
css
div.image-container {
  position: relative;   /* context for overlay */
  display: inline-block;
  width: 400px;
}

div.image-container img {
  display: block;
  width: 100%;
}

div.overlay-text {
  position: absolute;
  bottom: 16px;          /* 16px from the bottom of the container */
  left: 0;
  right: 0;
  text-align: center;
  background-color: rgba(0, 0, 0, 0.55);
  color: white;
  padding: 10px;
  font-size: 18px;
  font-family: Arial, sans-serif;
}

Expected output: A photo with a semi-transparent dark caption bar pinned to the bottom. This pattern is used on every photo gallery, travel website, and news card on the internet.

Tooltip Positioned Above a Button

html
<div class="tooltip-wrapper">
  <button>Hover me</button>
  <div class="tooltip">This is a tooltip!</div>
</div>
css
div.tooltip-wrapper {
  position: relative;
  display: inline-block;
}

div.tooltip {
  position: absolute;
  bottom: 110%;        /* Positions above the button */
  left: 50%;
  transform: translateX(-50%);   /* Centres the tooltip horizontally */
  background-color: #333;
  color: white;
  padding: 6px 12px;
  border-radius: 4px;
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
}

bottom: 110% explained: This sets the bottom edge of the tooltip to 110% of the parent's height above the parent's bottom edge. In practice: it floats the tooltip just above the button with a small gap.

left: 50% + transform: translateX(-50%) explained: left: 50% moves the tooltip's left edge to the midpoint of the parent. translateX(-50%) then shifts it back half of its own width · perfectly centring it over the parent. This is a classic CSS centring technique.


absolute vs fixed · Key Difference

Featureposition: absoluteposition: fixed
Reference pointNearest positioned ancestorBrowser viewport
Scrolls with page?Yes, it moves with the pageNo, it stays in view
Taken out of flow?YesYes
Common useBadges, tooltips, overlaysNavbars, floating buttons, banners

✏️ Your Task
left: 50% + transform: translateX(-50%) explained: left: 50% moves the tooltip's left edge to the midpoint of the parent. translateX(-50%) then shifts it back half of its own width · perfectly centring it over the parent. This is a classic CSS centring technique. ·
Phase 7 of 12
Part 5 · `position: sticky`

What is position: sticky?

position: sticky is a hybrid between relative and fixed. An element with position: sticky behaves like a relatively positioned element while it is within the visible scroll area, and then becomes fixed when it reaches a defined scroll threshold.

Analogy: Imagine a sticky note inside a long document. As you scroll down, it scrolls with you normally. But when it reaches the top of the visible window, it sticks there · refusing to scroll further until you reach the end of its parent container.

The Critical Rule for sticky

You must specify at least one offset property (top, bottom, left, or right) for sticky to work. The most common is top: 0 · which means "stick when you reach the top of the viewport."

css
div.sticky-header {
  position: sticky;
  top: 0;   /* Stick when the element reaches 0px from the top of the viewport */
  background-color: #fffde7;
  padding: 10px 20px;
  border-bottom: 2px solid #f9a825;
}

Full Sticky Demonstration

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      font-family: Arial, sans-serif;
    }

    /* The sticky element */
    div.section-header {
      position: sticky;
      top: 0;
      background-color: #1565c0;
      color: white;
      padding: 12px 20px;
      font-size: 18px;
      font-weight: bold;
      z-index: 10;
    }

    div.section-content {
      padding: 20px;
      background-color: #e3f2fd;
      height: 300px;   /* Tall enough to force scrolling */
    }
  </style>
</head>
<body>

  <!-- Section 1 -->
  <div class="section-header">Section 1: Introduction</div>
  <div class="section-content">
    <p>Lots of content in Section 1. Scroll down...</p>
  </div>

  <!-- Section 2 -->
  <div class="section-header">Section 2: Methods</div>
  <div class="section-content">
    <p>Lots of content in Section 2. Keep scrolling...</p>
  </div>

  <!-- Section 3 -->
  <div class="section-header">Section 3: Results</div>
  <div class="section-content">
    <p>Lots of content in Section 3.</p>
  </div>

</body>
</html>

Expected output: As you scroll down, each section header sticks to the top of the viewport while you scroll through that section's content. When the next section header arrives, it pushes the previous one off the top and takes its place. This is used on: alphabet index bars in contact lists, table headers in long data tables, progress indicators, and chapter navigation on long articles.

Thinking prompt: What happens if you change top: 0 to top: 60px? The element will only stick when it is 60px from the top · leaving 60px of space between the sticky element and the top of the viewport (useful if you have a fixed navbar that is 60px tall).

Sticky vs Fixed · Key Difference

Featureposition: stickyposition: fixed
Taken out of flow?No · still occupies original spaceYes · removed from flow
Scrolls with page?Yes, until thresholdNo, always fixed
Reference for offsetsScroll containerBrowser viewport
Content pushes down?Yes · other content flows around itNo · must add margin manually

Common sticky Gotcha · The Parent Must Be Tall Enough

A sticky element will only stick as long as it is within the bounds of its parent container. The moment the parent's bottom edge scrolls past the viewport, the sticky element unsticks and disappears with the parent.

html
<!-- BAD: parent is too short — sticky never works -->
<div style="height: 60px;">
  <div style="position: sticky; top: 0;">Header</div>
  <p>Short content</p>
</div>

<!-- GOOD: parent is tall enough for sticky to matter -->
<div style="height: 800px;">
  <div style="position: sticky; top: 0;">Header</div>
  <p>Lots of content here...</p>
</div>

✏️ Your Task
Practise what you just learned about position: sticky. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 8 of 12
Part 6 · Offset Properties Deep Dive

How top, bottom, left, right Work Together

You can use any combination of offset properties. Here is how each one behaves:

PropertyDirectionExample
top: 20pxPushes element 20px DOWN from its reference top edgeDown
top: -20pxPulls element 20px UPWARDUp
bottom: 20pxPositions element so its bottom is 20px from the reference bottomUp
left: 30pxPushes element 30px to the RIGHTRight
left: -30pxPulls element 30px to the LEFTLeft
right: 30pxPositions element so its right is 30px from the reference rightLeft

Centring with absolute · Classic Technique

To centre an absolute element both horizontally and vertically inside its positioned parent:

css
div.parent {
  position: relative;
  width: 400px;
  height: 300px;
  background-color: #e8f5e9;
}

div.centred-child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #43a047;
  color: white;
  padding: 16px 24px;
  border-radius: 6px;
}

How it works:

  • top: 50%; left: 50%; · moves the element's top-left corner to the exact centre of the parent
  • transform: translate(-50%, -50%) · shifts the element back by half its own width and height, perfectly centring it

Expected output: The green box appears exactly centred within the parent container regardless of how big either element is.


✏️ Your Task
Practise what you just learned about Offset Properties Deep Dive. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 9 of 12
Part 7 · The `z-index` Connection

When positioned elements overlap each other, CSS needs to decide which one appears on top. This is controlled by z-index. The element with the higher z-index appears in front.

css
div.layer-1 {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 1;           /* Lower — appears behind */
  background-color: lightblue;
}

div.layer-2 {
  position: absolute;
  top: 40px;
  left: 40px;
  z-index: 2;           /* Higher — appears in front */
  background-color: lightyellow;
}

Key rule: z-index only works on positioned elements (anything except position: static). It has no effect on static elements.


✏️ Your Task
Practise what you just learned about The z-index Connection. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 10 of 12
Part 8 · Code Challenge Walkthroughs

The W3Schools CSS position code challenges test your understanding of all five position values and their offset properties. Here are the core types:

Challenge Type 1: Set an Element to Relative and Offset It

Task: Move the element 15px down and 10px right from its normal position.

css
/* Solution */
div {
  position: relative;
  top: 15px;
  left: 10px;
}

Challenge Type 2: Create a Fixed Header

Task: Fix a header element to the top of the viewport, full width.

css
/* Solution */
header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
}

Challenge Type 3: Absolute Inside Relative Container

Task: Place a .label element at the bottom-right corner of its .container parent.

css
/* Solution */
.container {
  position: relative;
}

.label {
  position: absolute;
  bottom: 0;
  right: 0;
}

Challenge Type 4: Sticky Section Header

Task: Make a header stick to the top of the viewport when scrolled.

css
/* Solution */
h2 {
  position: sticky;
  top: 0;
}

Challenge Type 5: Centre an Absolute Element

Task: Centre a .popup box inside a .wrapper both horizontally and vertically.

css
/* Solution */
.wrapper {
  position: relative;
}

.popup {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

✏️ Your Task
### Challenge Type 1: Set an Element to Relative and Offset It Task: Move the element 15px down and 10px right from its normal position. `css /* Solution */ div { position: relative; top: 15px; left: 10px; } ` ·
Phase 11 of 12
Guided Practice Exercises
🎯 Your Challenge

Exercise 1 · Profile Card with Absolute Badge

Objective: Build a profile card where a "VERIFIED" badge is pinned to the top-right corner using position: absolute on a position: relative container.

Scenario: You are building a user profile card for a social platform. Users who have verified their email get a badge pinned to the card corner.

Starter HTML:

✏️ 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>
    /* Write your CSS here */
  </style>
</head>
<body>

  <div class="profile-card">
    <div class="badge">✓ VERIFIED</div>
    <div class="avatar">👤</div>
    <h3>Alex Johnson</h3>
    <p>Frontend Developer</p>
  </div>

</body>
</html>

Target styling:

  • .profile-card: position: relative, white background, width: 240px, padding: 30px 20px, border-radius: 12px, box shadow, text-align: center
  • .badge: position: absolute, top: 12px, right: 12px, green background (#2e7d32), white text, small font, rounded pill shape

Solution:

css
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background-color: #f0f2f5; display: flex; justify-content: center; padding: 60px 20px; font-family: Arial, sans-serif; }

.profile-card {
  position: relative;       /* Establishes context for .badge */
  background-color: white;
  width: 240px;
  padding: 30px 20px;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.1);
  text-align: center;
}

.badge {
  position: absolute;       /* Positioned relative to .profile-card */
  top: 12px;
  right: 12px;
  background-color: #2e7d32;
  color: white;
  font-size: 11px;
  font-weight: bold;
  padding: 4px 10px;
  border-radius: 20px;
}

.avatar {
  font-size: 52px;
  margin-bottom: 12px;
}

h3 { font-size: 18px; color: #222; margin-bottom: 4px; }
p  { font-size: 14px; color: #777; }

Expected output: A white profile card centred on a grey background, with a small green "✓ VERIFIED" pill badge locked to the top-right corner.

Self-check questions:

  • Does the badge stay in the corner even if you change the card's width?
  • What happens if you remove position: relative from .profile-card? (The badge jumps to the corner of the whole page.)

Exercise 2 · Fixed Navigation + Sticky Section Headers

Objective: Build a page with a fixed top navigation bar and sticky section headers that lock at the viewport top as you scroll.

Scenario: You are building a long documentation page with a fixed navbar and sticky chapter headers.

Solution:

html
<!DOCTYPE html>
<html>
<head>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: Arial, sans-serif; }

    /* Fixed navbar — always at top of viewport */
    nav.topbar {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      background-color: #0d47a1;
      color: white;
      padding: 16px 24px;
      font-size: 18px;
      font-weight: bold;
      z-index: 1000;
    }

    /* Push content below the fixed navbar */
    main {
      margin-top: 54px;
    }

    /* Sticky chapter header */
    h2.chapter {
      position: sticky;
      top: 54px;    /* sticks just below the fixed navbar (54px = navbar height) */
      background-color: #e8eaf6;
      color: #283593;
      padding: 10px 24px;
      font-size: 17px;
      border-left: 4px solid #3949ab;
      z-index: 100;
    }

    div.chapter-content {
      padding: 30px 24px;
      background-color: white;
      min-height: 320px;
      border-bottom: 1px solid #e0e0e0;
    }

    p { margin-bottom: 14px; color: #444; line-height: 1.7; }
  </style>
</head>
<body>

  <nav class="topbar">📘 CSS Documentation</nav>

  <main>

    <h2 class="chapter">Chapter 1: Introduction to CSS</h2>
    <div class="chapter-content">
      <p>CSS stands for Cascading Style Sheets. It describes how HTML elements are displayed on screen. Scroll down to continue reading about CSS fundamentals.</p>
      <p>With CSS, you control the layout, colour, spacing, fonts, and visual effects of every element on your web page.</p>
      <p>CSS can be added inline, internally, or via an external stylesheet.</p>
    </div>

    <h2 class="chapter">Chapter 2: Selectors</h2>
    <div class="chapter-content">
      <p>Selectors are patterns used to target HTML elements you want to style.</p>
      <p>Types include element selectors, class selectors, ID selectors, attribute selectors, and pseudo-class selectors.</p>
      <p>Understanding selector specificity is crucial for writing predictable, maintainable CSS.</p>
    </div>

    <h2 class="chapter">Chapter 3: The Box Model</h2>
    <div class="chapter-content">
      <p>Every HTML element is a rectangular box with content, padding, border, and margin.</p>
      <p>The box model determines how space is calculated and distributed around elements.</p>
      <p>Use `box-sizing: border-box` to include padding and border in the element's total width.</p>
    </div>

    <h2 class="chapter">Chapter 4: Positioning</h2>
    <div class="chapter-content">
      <p>CSS positioning includes static, relative, fixed, absolute, and sticky.</p>
      <p>Understanding positioning is one of the most powerful skills in CSS layout design.</p>
      <p>The `position: relative` + `position: absolute` pattern is used on almost every production website.</p>
    </div>

  </main>

</body>
</html>

Expected output:

  • A fixed dark blue navbar always visible at the top
  • Each chapter header sticks just below the navbar as you scroll through that chapter's content
  • As the next chapter arrives, its header pushes the previous one up and takes its sticky position

Exercise 3 · Image Card with Overlay Text

Objective: Build an image card where text overlays the bottom of the image using position: absolute on a position: relative wrapper.

Solution:

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial, sans-serif; background: #f5f5f5; padding: 40px; }

    .photo-card {
      position: relative;
      width: 340px;
      border-radius: 10px;
      overflow: hidden;       /* clips the overlay to the card's rounded corners */
      box-shadow: 0 6px 20px rgba(0,0,0,0.15);
    }

    .photo-card img {
      display: block;
      width: 100%;
      height: 220px;
      object-fit: cover;      /* fills the space without distortion */
      background-color: #90caf9;  /* placeholder if no actual image */
    }

    /* Simulated image using a div (for demo without real image file) */
    .fake-image {
      display: block;
      width: 100%;
      height: 220px;
      background: linear-gradient(135deg, #1565c0, #42a5f5);
    }

    .caption {
      position: absolute;
      bottom: 0;              /* Pinned to the bottom of .photo-card */
      left: 0;
      right: 0;
      background: linear-gradient(transparent, rgba(0,0,0,0.75));
      color: white;
      padding: 24px 16px 16px;
    }

    .caption h3 { font-size: 17px; margin-bottom: 4px; }
    .caption p  { font-size: 13px; opacity: 0.85; }
  </style>
</head>
<body>

  <div class="photo-card">
    <div class="fake-image"></div>
    <div class="caption">
      <h3>Mountain Sunrise</h3>
      <p>Swiss Alps · Photography by Sarah K.</p>
    </div>
  </div>

</body>
</html>

Expected output: A rounded photo card with a gradient-fading dark overlay at the bottom containing a title and description. The gradient fades from transparent at the top to semi-black at the bottom · a technique used on every photo card on Instagram, Unsplash, and news sites.


Phase 12 of 12
Common Beginner Mistakes

Mistake 1: Using Offsets on a Static Element

Wrong:

css
div {
  top: 50px;    /* Does nothing! */
  left: 30px;   /* Does nothing! */
}

Problem: No position property was set. Default is static. Offset properties are completely ignored on static elements.

Correct:

css
div {
  position: relative;  /* or absolute, fixed, sticky */
  top: 50px;
  left: 30px;
}

Mistake 2: Forgetting to Compensate for Fixed Elements

Wrong:

css
nav { position: fixed; top: 0; height: 60px; }
/* No margin-top on body or main content */

Problem: Fixed elements are removed from document flow. The content behind them starts at the very top · hidden beneath the fixed nav.

Correct:

css
nav { position: fixed; top: 0; height: 60px; }
main { margin-top: 60px; }   /* Push content below the fixed nav */

Mistake 3: Expecting absolute to Position Inside the Wrong Parent

Wrong:

html
<div class="wrapper">         <!-- no position set -->
  <div class="parent">        <!-- no position set -->
    <div class="child" style="position: absolute; top: 0; right: 0;">Badge</div>
  </div>
</div>

Problem: The badge positions relative to the nearest positioned ancestor · but neither .parent nor .wrapper has a non-static position. The badge jumps to the corner of the entire page.

Correct:

css
.parent {
  position: relative;   /* Now .child positions inside .parent */
}

Mistake 4: sticky Not Working · Forgetting the Offset

Wrong:

css
div.header {
  position: sticky;    /* sticky without an offset does nothing */
}

Problem: Without specifying top, bottom, left, or right, the browser does not know at what scroll point to make it stick.

Correct:

css
div.header {
  position: sticky;
  top: 0;   /* Stick when element reaches 0px from top of viewport */
}

Mistake 5: sticky Not Working · Parent Is Too Short or Has overflow: hidden

Wrong setup:

css
.section {
  overflow: hidden;   /* This BREAKS sticky positioning */
}
.section h2 {
  position: sticky;
  top: 0;
}

Problem 1: If the parent container has overflow: hidden or overflow: auto, sticky cannot work · it needs a scroll container, and setting overflow on the parent prevents the sticky behaviour.

Problem 2: If the parent is too short (the sticky element fills most of its height), there is nothing to scroll through, so sticky never activates.

Correct: Ensure the sticky element's parent does not have overflow: hidden/auto and is taller than the sticky element.


Mistake 6: z-index Not Working on Static Elements

Wrong:

css
div.overlay {
  z-index: 999;   /* Does nothing — div is position: static */
}

Problem: z-index only works on positioned elements (non-static). On a static element, it is completely ignored.

Correct:

css
div.overlay {
  position: relative;   /* or absolute, fixed, sticky */
  z-index: 999;         /* Now works */
}

✏️ 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

Project Overview

You will build a complete hero section for a personal portfolio website. It includes: a fixed navigation bar at the top, a hero background with absolutely positioned text and a call-to-action button, and a sticky section label that locks when you scroll into the about section.

This project uses fixed, absolute, relative, and sticky all in one cohesive page.


Stage 1 · HTML Structure

starter.html
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Alex Chen — Portfolio</title>
  <style>
    /* CSS added stage by stage below */
  </style>
</head>
<body>

  <!-- Fixed navigation -->
  <nav class="main-nav">
    <span class="logo">Alex Chen</span>
    <div class="nav-links">
      <a href="#hero">Home</a>
      <a href="#about">About</a>
      <a href="#work">Work</a>
      <a href="#contact">Contact</a>
    </div>
  </nav>

  <!-- Hero section with absolute overlay text -->
  <section id="hero" class="hero-section">
    <div class="hero-content">
      <span class="tag">Full-Stack Developer</span>
      <h1>Building the Web,<br>One Line at a Time.</h1>
      <p>I create clean, fast, and accessible web experiences.</p>
      <a href="#work" class="cta-btn">View My Work →</a>
    </div>

    <!-- Absolutely positioned decorative badge -->
    <div class="scroll-hint">↓ Scroll</div>
  </section>

  <!-- About section with sticky header -->
  <section id="about" class="about-section">
    <h2 class="sticky-label">About Me</h2>
    <div class="about-content">
      <p>I am a passionate developer with 5 years of experience building modern web applications using HTML, CSS, JavaScript, and React.</p>
      <p>I care deeply about performance, accessibility, and writing code that other developers enjoy reading.</p>
      <p>When I am not coding, I am hiking, reading, or experimenting with new technologies.</p>
      <p>I believe great software starts with clear thinking and a genuine understanding of user needs.</p>
    </div>
  </section>

  <!-- Work section placeholder -->
  <section id="work" class="work-section">
    <h2 class="sticky-label">My Work</h2>
    <div class="about-content">
      <p>Project cards will go here in a future lesson on CSS Grid and Flexbox.</p>
      <p>For now, imagine three beautiful project cards displayed side by side.</p>
      <p>Each one showcases a different type of project — web app, mobile UI, and data dashboard.</p>
      <p>Every card uses the `position: relative` + `position: absolute` badge pattern you learned today.</p>
    </div>
  </section>

</body>
</html>

Lesson 21 complete! 🎉

You covered: