Python · SQL · Web Dev · Java · AI/ML tracks launching soon — your one platform for all of IT
Beginner+250 XP

Building a Complete Static Page

A full project pulling structure, semantics, media, and forms together into one real, complete HTML page — start to finish.

50 min August 2026
// The Phase 2 Capstone

Everything From Modules 1–15, in One Real Page

This module is different from the previous 15 — instead of introducing a new topic, it builds one complete, real page from start to finish: a small local business landing page (a fictional coffee roastery), combining document structure, semantic sectioning, images, navigation, a contact form, and metadata into a single genuine build. Every technique used here was already covered in an earlier module — this is deliberately a synthesis, not new material, and each section below names exactly which earlier module it draws from.

// Part 01 — Planning the Page

What We're Building, and Why Structure Comes First

Before writing a single tag, sketch the page's actual sections: a header with navigation, a hero introduction, an "About" section, a "Menu" section with a list of offerings, a contact section with a real form, and a footer. This maps directly onto the semantic landmark elements from Module 3 — deciding the sections BEFORE writing markup is what keeps the result genuinely semantic instead of div-soup with classes bolted on afterward.

The page's planned outline
header (site branding + nav)
main
  section (hero — page title + one-line pitch)
  section (about the roastery)
  section (the menu — a real content list)
  section (contact — a real working form)
footer (copyright + secondary links)
// Part 02 — The Document Skeleton

Starting From Module 2's Foundation

The full document shell — DOCTYPE, head, and metadata from Modules 2 and 13
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Fernwood Coffee Roastery — Small-Batch, Portland OR</title>
  <meta name="description" content="Small-batch, ethically-sourced coffee roasted weekly in Portland, Oregon. Visit our roastery or order online.">
  <link rel="icon" href="/favicon.ico">
</head>
<body>
  <!-- page content goes here -->
</body>
</html>

Every piece here traces back to an earlier module: the DOCTYPE and lang attribute (Module 2), the charset and viewport meta tags (Modules 2 and 13), and the title/description tags that determine how this page appears in search results and browser tabs (Module 13).

// Part 03 — Header and Navigation

Building From Modules 3 and 4

A real semantic header, using landmark elements and a proper nav list
<header>
  <a href="/" class="logo">Fernwood Coffee Roastery</a>
  <nav aria-label="Main navigation">
    <ul>
      <li><a href="#about">About</a></li>
      <li><a href="#menu">Menu</a></li>
      <li><a href="#contact">Contact</a></li>
    </ul>
  </nav>
</header>

The <nav> landmark and the <ul> list structure inside it are exactly the pattern from Module 3 (semantic structure) and Module 4 (links & navigation) — the in-page #about/#menu/#contact links use the anchor links technique from Module 4, targeting the id attributes each section below will carry.

// Part 04 — The Hero and About Sections

Text Hierarchy From Module 3, Images From Module 5

The hero — the one-and-only h1 on the page
<main>
  <section aria-labelledby="hero-heading">
    <h1 id="hero-heading">Small-Batch Coffee, Roasted Weekly</h1>
    <p>Ethically sourced, roasted in small batches every Tuesday in Portland, Oregon.</p>
  </section>

  <section id="about" aria-labelledby="about-heading">
    <h2 id="about-heading">About Fernwood</h2>
    <figure>
      <img src="/roastery-interior.jpg"
           alt="The Fernwood roastery's interior, with a large drum roaster and bags of green coffee beans"
           width="800" height="500" loading="lazy">
      <figcaption>Our roastery on SE Belmont Street, open for tours every Saturday.</figcaption>
    </figure>
    <p>Founded in 2019, Fernwood roasts small batches of ethically sourced beans every week...</p>
  </section>
🎯 Pro Tip
Notice there is exactly one h1 on the entire page — a direct application of the heading-hierarchy rule from Module 3. Every section below uses h2 for its own heading, maintaining a single, sensible document outline from top to bottom.

The image follows the complete pattern from Module 5: real, descriptive alt text (not decorative — this image genuinely conveys information), explicit width/height to prevent layout shift, wrapped in figure/figcaption for a captioned image, and loading="lazy" since this image sits below the initial viewport.

// Part 05 — The Menu Section

A Real Content List, From Module 6

An unordered list used for genuinely unordered content — the menu items
<section id="menu" aria-labelledby="menu-heading">
  <h2 id="menu-heading">This Week's Roast</h2>
  <ul>
    <li>
      <h3>Ethiopia Yirgacheffe</h3>
      <p>Bright, floral, notes of bergamot and stone fruit. Light roast.</p>
    </li>
    <li>
      <h3>Colombia Huila</h3>
      <p>Balanced, caramel sweetness, a clean finish. Medium roast.</p>
    </li>
    <li>
      <h3>Sumatra Mandheling</h3>
      <p>Full-bodied, earthy, low acidity. Dark roast.</p>
    </li>
  </ul>
</section>

<ul> is the correct choice here (rather than <ol>) because this week's roast list has no meaningful order — Module 6's core distinction between the two list types applied directly to a real decision.

// Part 06 — The Contact Form

A Genuinely Accessible Form, From Modules 8, 9 and 10

A real, working contact form
<section id="contact" aria-labelledby="contact-heading">
  <h2 id="contact-heading">Get in Touch</h2>
  <form action="/submit-contact" method="POST">
    <div>
      <label for="contact-name">Name</label>
      <input type="text" id="contact-name" name="name" required>
    </div>
    <div>
      <label for="contact-email">Email</label>
      <input type="email" id="contact-email" name="email" required>
    </div>
    <fieldset>
      <legend>What are you reaching out about?</legend>
      <label><input type="radio" name="reason" value="wholesale"> Wholesale orders</label>
      <label><input type="radio" name="reason" value="visit"> Visiting the roastery</label>
      <label><input type="radio" name="reason" value="other" checked> Something else</label>
    </fieldset>
    <div>
      <label for="contact-message">Message</label>
      <textarea id="contact-message" name="message" rows="5" required></textarea>
    </div>
    <button type="submit">Send Message</button>
  </form>
</section>

Every field is correctly labeled (Module 8), the reason-for-contact question uses a real fieldset/legend-grouped radio set (Module 9), and every input that matters for the business to receive has a name attribute — the single most common real mistake flagged in Module 8's own Real World example, deliberately avoided here.

// Part 07 — The Footer

Closing Out the Page

A simple, real footer
  <footer>
    <p>&copy; 2026 Fernwood Coffee Roastery. All rights reserved.</p>
    <nav aria-label="Footer navigation">
      <ul>
        <li><a href="/privacy">Privacy Policy</a></li>
        <li><a href="/terms">Terms of Service</a></li>
      </ul>
    </nav>
  </footer>
</main>

The &copy; entity here is a direct callback to Module 14 — a literal © character can be typed directly in most editors today, but the entity form remains common in real production code and is always guaranteed to render correctly regardless of the file's declared encoding.

// Part 08 — Validating the Result

Checking the Finished Page Against Module 15

With the full page assembled, running it through the W3C Markup Validator (Module 15) is the final step before considering it done — checking for unclosed tags, duplicate IDs (a real risk here, since both the header and footer navigation reuse similar list structures), and any invalid nesting introduced while assembling the sections.

🎯 Pro Tip
A genuinely useful validation habit: check every id attribute is unique across the whole page. This build uses several — hero-heading, about-heading, menu-heading, contact-heading, contact-name, contact-email, contact-message — a quick scan (or the validator) confirms none collide, which matters because a duplicate ID breaks label for associations silently, exactly as covered in Module 8.
// Real World
💼 What This Looks Like at Work

A Real Freelance Client Site Built From Exactly This Pattern

Scenario — Freelance web developer, Austin · Small business site delivery

A freelance developer is hired to build a landing page for a local bakery — genuinely the same shape of project as this module's build. The client later asks why their site ranks reasonably well in local Google searches despite having no marketing budget at all.

What actually drove that result

The exact fundamentals from this module — a single clear h1, a real semantic document structure search engines can parse confidently, a proper meta description, and real descriptive alt text on every image — are themselves meaningful, genuine SEO signals, with zero paid marketing involved. The developer's own explanation to the client: "there's no trick here — this is just what a well-structured page looks like to a search engine, and most sites built quickly without attention to this structure never get it for free."

// Misconceptions

Four Misconceptions About Assembling a Real Page

"A page is semantic as long as it uses SOME semantic tags somewhere"
A single <nav> buried in an otherwise all-div layout does not make the page semantic — semantic structure is a choice made at the PLANNING stage, section by section, not a tag sprinkled in afterward for credit.
"Validating the finished HTML is optional if the page visually looks correct in a browser"
A browser silently tolerates a huge range of invalid HTML (unclosed tags, duplicate IDs) by guessing what was intended — the page can look fine while still breaking label associations or confusing assistive technology, exactly the kind of bug the validator catches that visual inspection cannot.
"Combining every technique from earlier modules automatically produces good code if each piece was correct individually"
Individually correct pieces can still combine badly — a duplicate id reused between the header and footer nav lists is a real risk that only shows up when the WHOLE page is assembled, not when any single section was tested alone.
"SEO requires separate technical work beyond just building the page well"
Strong fundamentals — one clear h1, real semantic structure, a proper meta description, genuine alt text — are themselves meaningful SEO signals with zero additional work, exactly as shown in the Real World example above.
// Interview Prep

4 Interview Questions — With Complete Answers

Why plan a page's sections before writing any markup?
Deciding the semantic sections up front (header, nav, main, the individual sections, footer) is what keeps the result genuinely meaningful HTML rather than a layout of generic divs with classes bolted on to describe what they visually look like rather than what they actually are.
Why is exactly one h1 per page a real rule, not just a style preference?
The h1 establishes the top of the page's document outline — search engines and assistive technology use heading hierarchy to understand structure, and multiple h1s (or skipped heading levels) genuinely confuse that structure rather than merely looking stylistically inconsistent.
What real risk does combining several sections built independently introduce?
Duplicate id attributes — each section might look correct in isolation, but ids must be unique across the WHOLE assembled page, and a collision (e.g. two sections both using an id like "heading") silently breaks any label association or anchor link relying on that id.
What concrete, no-extra-work SEO benefit comes from just building a page with strong HTML fundamentals?
A single clear h1, real semantic sectioning, a proper meta description, and genuine descriptive alt text on every image are themselves meaningful ranking signals search engines use to understand a page — no separate "SEO work" layer is required beyond building the page well in the first place.
// Common Mistakes

Mistakes Beginners Make Assembling a Real Page

Reusing the same id across the header and footer navigation lists
ids must be unique across the entire document — reusing one between visually similar sections (like two nav lists) silently breaks anchor links and label associations relying on that id.
Writing markup section by section without a plan, then trying to make it semantic afterward
Retrofitting semantics onto an already-built div-based layout tends to produce shallow, inconsistent results — planning the semantic sections up front produces a genuinely more coherent document outline.
Skipping the final validator pass because the page "looks right" in the browser
Browsers silently tolerate a wide range of invalid HTML — a page can render correctly while still having structural bugs (duplicate ids, unclosed tags) that only the validator, not visual inspection, will catch.
Forgetting a name attribute on a real contact form field while assembling a full page
Exactly the most common real bug flagged back in the Forms module — an unnamed input renders and accepts input normally but is silently excluded from what actually gets submitted.
// Error Library

Issues You Will Hit Assembling a Real Page — And Exactly Why

A <label for="..."> stops working after combining several sections into one page
Cause: Two separate sections, each correct on its own, happen to reuse the same id value once combined — the browser associates the label with whichever matching id appears first in the document, not necessarily the intended input.
Fix: Give every id a genuinely unique value across the whole page, ideally prefixed by section (e.g. contact-name rather than just name) to avoid collisions as the page grows.
Duplicate ID "..." (from the W3C Markup Validator)
Cause: Exactly the collision described above — the validator catches this even when the browser itself renders the page without any visible error.
Fix: Search the full page source for every instance of the flagged id and rename all but one to something unique.
A contact form silently fails to include a field in its submission, with no error shown anywhere
Cause: A missing name attribute on that specific input — easy to miss while assembling many sections quickly.
Fix: Check every real input in the assembled page has both a name and a properly associated label before considering the build done.

🎯 Key Takeaways

  • A real page starts with planning its sections BEFORE writing markup — that planning is what keeps the result genuinely semantic instead of div-soup with classes added afterward.
  • Every technique in this build traces back to an earlier module: document structure (Module 2), semantic sectioning (Module 3), navigation (Module 4), images (Module 5), lists (Module 6), forms (Modules 8-9), entities (Module 14), and metadata (Module 13).
  • Exactly one h1 per page, with h2/h3 used consistently for every section's own heading, keeps the document outline sensible from top to bottom.
  • Every form field needs both a real associated label AND a name attribute — the single most common real-world mistake this build deliberately avoids.
  • Validating the finished page (Module 15) — especially checking for duplicate IDs — is the correct final step before considering a real build done.
  • Strong semantic HTML fundamentals are themselves a genuine, free SEO signal — not a separate technique layered on top afterward.

What comes next

Phase 3 begins here — CSS Foundations, starting with how CSS actually applies styles: syntax, selectors, and the cascade.

Module 17 → What is CSS? Syntax, Selectors & the Cascade
Share

Discussion

0

Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.

Continue with GitHub
Loading...