Lecture 1 / 12
Lecture 01 · Foundations

What is HTML?

Beginner ~40 min No prerequisites

Introduction to HTML

HTML stands for HyperText Markup Language. It is the standard language used to create and structure content on the web. Every webpage you visit — from Google to Wikipedia — is built on HTML at its core.

HTML is not a programming language. It is a markup language: it uses tags to annotate and describe the meaning of content, telling the browser how to display text, images, links, and other elements.

A brief history

How Browsers Work

When you visit a website, the browser sends an HTTP request to a server. The server responds with an HTML file. The browser then parses the HTML, builds a DOM (Document Object Model), and renders the page on screen.

ℹ️ The DOM
The Document Object Model is a tree-like representation of your HTML page in memory. JavaScript and CSS interact with the page through the DOM.

Your First HTML File

Create a file called index.html in any text editor. VS Code is recommended — install the Live Server extension to see changes in real time.

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My First Page</title>
</head>
<body>
    <h1>Hello, World!</h1>
    <p>Welcome to HTML Mastery.</p>
</body>
</html>
⬛ Browser Preview index.html

Hello, World!

Welcome to HTML Mastery.

Anatomy of an HTML Tag

HTML is built from elements. Most elements have an opening tag, content, and a closing tag:

<p class="intro">Hello!</p>
p
Tag name
class
Attribute
"intro"
Value
Hello!
Content

Self-closing (void) elements

Some elements have no content and don't need a closing tag. These are called void elements:

void_elements.html
<br>         <!-- line break -->
<hr>         <!-- horizontal rule -->
<img src="photo.jpg">  <!-- image -->
<input type="text">   <!-- form input -->
<meta charset="UTF-8">

HTML Comments

comments.html
<!-- This is a single-line comment — browsers ignore it -->

<!--
  Multi-line comments work too.
  Great for temporarily hiding code or leaving notes.
-->

<p>This text is visible.</p>
<!-- <p>This paragraph is hidden!</p> -->
✅ Best Practice
Use comments to explain why certain HTML decisions were made — especially for complex layouts or accessibility-related markup.
🎯 Exercise 1.1

Create an index.html file. Add a heading with your name, a paragraph describing yourself, and run it in your browser. Inspect the page using browser DevTools (F12) and look at the DOM tree.

🎯 Exercise 1.2

Write an HTML file with at least 3 different void elements. Add comments explaining what each one does. View the page source in your browser (Ctrl+U / Cmd+U).

Lecture 02 · Foundations

Document Structure

Beginner ~45 min Requires: Lecture 01

The HTML Boilerplate

Every valid HTML5 document follows the same fundamental structure. Understanding each part is essential before writing any real content.

boilerplate.html
<!DOCTYPE html>                   <!-- declares HTML5 -->
<html lang="en">                  <!-- root element; lang for accessibility -->

<head>                              <!-- metadata: not visible to the user -->
    <meta charset="UTF-8">          <!-- character encoding -->
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0">
    <title>Page Title</title>          <!-- shown in browser tab -->
    <link rel="stylesheet" href="style.css">
</head>

<body>                              <!-- all visible content goes here -->
    <h1>Page Heading</h1>
    <p>Main content...</p>

    <script src="app.js"></script>   <!-- JS goes at end of body -->
</body>
</html>

The <head> Element

The <head> contains metadata — information about the page that isn't displayed to users. Here are the key elements you'll put inside it:

Tag Purpose Example
<meta charset> Character encoding charset="UTF-8"
<meta viewport> Mobile responsiveness width=device-width
<title> Browser tab / SEO title My Website
<link> Link CSS files, favicons rel="stylesheet"
<style> Inline CSS CSS directly in HTML
<script> JavaScript Usually at end of body
<meta name> SEO, description, author name="description"

Linking CSS & JavaScript

linking.html
<head>
    <!-- External CSS -->
    <link rel="stylesheet" href="style.css">

    <!-- Google Fonts -->
    <link rel="preconnect" href="https://fonts.googleapis.com">

    <!-- Inline CSS (avoid for large projects) -->
    <style>
        body { background: #f0f0f0; }
    </style>
</head>
<body>
    <!-- Content here -->

    <!-- JS at bottom so HTML loads first -->
    <script src="app.js"></script>
</body>
⚠️ Script placement matters
Place <script> tags at the bottom of <body> so they don't block HTML from rendering. Alternatively, use the defer attribute: <script src="app.js" defer>.

Block vs Inline Elements

HTML elements fall into two display categories. Understanding this is fundamental to page layout.

Type Behaviour Examples
Block Starts on a new line; takes full width div, p, h1-h6, ul, li, table, form
Inline Flows with text; only as wide as content span, a, strong, em, img, input
🎯 Exercise 2.1

Build a complete valid HTML5 page with: a correct doctype, a <title>, a viewport meta tag, a linked stylesheet (even if the CSS file is empty), and meaningful body content. Validate it at validator.w3.org.

Lecture 03 · Foundations

Text & Typography

Beginner ~50 min Requires: Lecture 02

Headings

HTML provides six heading levels, <h1> through <h6>. Only use one <h1> per page — it signals the main topic to search engines and screen readers.

headings.html
<h1>Main Page Title (use once)</h1>
<h2>Section Heading</h2>
<h3>Sub-section</h3>
<h4>Sub-sub-section</h4>
<h5>Rarely needed</h5>
<h6>Almost never used</h6>
⬛ Browser Previewheadings.html

Main Page Title (use once)

Section Heading

Sub-section

Paragraphs & Line Breaks

text.html
<p>This is a paragraph. Browsers automatically add space above and below it.</p>

<p>This is another paragraph.<br>
This text is on a new line within the same paragraph.</p>

<hr>  <!-- horizontal divider line -->

<pre>
  This text    preserves
  spacing  and  line breaks.
</pre>

Text Formatting Tags

formatting.html
<strong>Bold / important</strong>   <!-- semantic importance -->
<b>Bold (presentational)</b>       <!-- no semantic meaning -->

<em>Italic / emphasis</em>         <!-- semantic stress -->
<i>Italic (presentational)</i>     <!-- e.g. technical terms -->

<u>Underline</u>                   <!-- use sparingly -->
<s>Strikethrough</s>
<mark>Highlighted text</mark>
<small>Fine print</small>
<sup>Superscript</sup>  <sub>Subscript</sub>

<code>inline code</code>
<kbd>Ctrl+C</kbd>               <!-- keyboard input -->
<abbr title="HyperText Markup Language">HTML</abbr>

<blockquote>
    A long quoted passage from another source.
</blockquote>

<q>A short inline quote.</q>
⬛ Browser Previewformatting.html

Bold / important   Italic / emphasis   Highlighted   Strikethrough

H2O and E = mc2   inline code   Ctrl+C

A long quoted passage from another source.
✅ Semantic vs Presentational
Prefer <strong> over <b> and <em> over <i>. Semantic tags convey meaning, not just appearance — crucial for screen readers and SEO.
🎯 Exercise 3.1 — Article Page

Create an HTML page that looks like a blog article. It should have: an <h1> title, at least 3 paragraphs, proper use of <strong>, <em>, a <blockquote>, and a <code> snippet.

Lecture 04 · Foundations

Links & Navigation

Beginner ~45 min Requires: Lecture 03

The Anchor Tag

The <a> (anchor) element creates hyperlinks. The href attribute specifies the destination.

links.html
<!-- External link -->
<a href="https://www.example.com">Visit Example</a>

<!-- Open in new tab -->
<a href="https://www.example.com" target="_blank"
   rel="noopener noreferrer">Open in New Tab</a>

<!-- Internal (relative) link -->
<a href="about.html">About Us</a>

<!-- Link to a page section (anchor) -->
<a href="#contact">Jump to Contact</a>
<section id="contact">...</section>

<!-- Email link -->
<a href="mailto:hello@example.com">Email Us</a>

<!-- Phone link -->
<a href="tel:+1234567890">Call Us</a>

<!-- Download link -->
<a href="report.pdf" download>Download PDF</a>
⚠️ Security: rel="noopener noreferrer"
Always add rel="noopener noreferrer" when using target="_blank". Without it, the opened page can access your page via window.opener — a security risk.

Navigation Menus

nav.html
<nav aria-label="Main navigation">
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/blog">Blog</a></li>
        <li><a href="/contact">Contact</a></li>
    </ul>
</nav>

Absolute vs Relative Paths

Path Type Example When to Use
Absolute https://example.com/page.html Linking to external sites
Root-relative /about.html Same site, from root
Relative ../images/logo.png Relative to current file
Anchor #section-id Jump within page
🎯 Exercise 4.1 — Multi-page Site

Create two HTML pages: index.html and about.html. Link them together with a navigation menu. Add a "mailto:" link and a "#" anchor that jumps to a section on the same page.

Lecture 05 · Foundations

Images & Media

Beginner ~50 min Requires: Lecture 04

The <img> Element

Images are embedded with the self-closing <img> tag. The alt attribute is not optional — it's required for accessibility and SEO.

images.html
<!-- Basic image -->
<img src="photo.jpg" alt="A scenic mountain landscape">

<!-- With dimensions (prevents layout shift) -->
<img src="logo.png" alt="Company Logo"
     width="200" height="80">

<!-- Lazy loading (improves performance) -->
<img src="hero.jpg" alt="Hero banner" loading="lazy">

<!-- Responsive image with srcset -->
<img src="photo-800.jpg"
     srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
     sizes="(max-width: 600px) 400px, 800px"
     alt="Responsive photo">

<!-- Figure with caption -->
<figure>
    <img src="chart.png" alt="Sales chart for Q3 2024">
    <figcaption>Fig. 1 — Q3 2024 Sales Results</figcaption>
</figure>

Image Formats Cheat Sheet

Format Best For Supports Transparency
JPEG / JPG Photos, complex images
PNG Logos, icons, screenshots
WebP Modern web — photos & graphics
SVG Icons, logos (vector)
AVIF Next-gen compression (best quality)
GIF Simple animations (prefer WebP/video) ✅ (1-bit)

Audio & Video

media.html
<!-- Audio -->
<audio controls>
    <source src="song.mp3" type="audio/mpeg">
    <source src="song.ogg" type="audio/ogg">
    Your browser does not support audio.
</audio>

<!-- Video -->
<video width="640" height="360" controls poster="thumb.jpg">
    <source src="video.mp4" type="video/mp4">
    <source src="video.webm" type="video/webm">
    <!-- Subtitles -->
    <track src="subs.vtt" kind="subtitles" srclang="en" label="English">
</video>

<!-- Embed YouTube (iframe) -->
<iframe width="560" height="315"
        src="https://www.youtube.com/embed/VIDEO_ID"
        title="YouTube video"
        allowfullscreen>
</iframe>
🎯 Exercise 5.1 — Gallery Page

Build an image gallery page with at least 4 images using <figure> and <figcaption>. Give all images meaningful alt text. Use loading="lazy" on images below the fold.

Lecture 06 · Core Concepts

Lists & Tables

Beginner ~45 min Requires: Lecture 05

Unordered Lists

lists.html
<ul>
    <li>Apples</li>
    <li>Bananas</li>
    <li>Cherries
        <ul>  <!-- nested list -->
            <li>Sweet cherry</li>
            <li>Sour cherry</li>
        </ul>
    </li>
</ul>

<!-- Ordered list -->
<ol start="3">  <!-- start at 3 -->
    <li>Third item</li>
    <li>Fourth item</li>
</ol>

<!-- Description list -->
<dl>
    <dt>HTML</dt>
    <dd>HyperText Markup Language</dd>
    <dt>CSS</dt>
    <dd>Cascading Style Sheets</dd>
</dl>

Tables

Use tables for tabular data — never for page layout. A proper table has a <thead>, <tbody>, and often a <tfoot>.

table.html
<table>
    <caption>Monthly Sales Report</caption>
    <thead>
        <tr>
            <th scope="col">Month</th>
            <th scope="col">Revenue</th>
            <th scope="col">Growth</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>January</td>
            <td>$12,400</td>
            <td>+8%</td>
        </tr>
        <tr>
            <td>February</td>
            <td colspan="2">Data unavailable</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td>Total</td>
            <td>$12,400</td>
            <td></td>
        </tr>
    </tfoot>
</table>
⬛ Browser Previewtable.html
Monthly Sales Report
Month Revenue Growth
January $12,400 +8%
February Data unavailable
Total $12,400
🎯 Exercise 6.1 — Data Table

Create a table of your favourite films: title, year, director, genre. Include proper <thead>, <tbody>, <caption>, and scope attributes on <th> elements.

Lecture 07 · Core Concepts

Forms & Inputs

Intermediate ~65 min Requires: Lecture 06

The <form> Element

Forms collect user input. The action attribute specifies where data is sent; method defines how it's sent (GET or POST).

form_basic.html
<form action="/submit" method="POST">

    <label for="name">Full Name</label>
    <input type="text" id="name" name="name"
           placeholder="Alice Smith" required>

    <label for="email">Email</label>
    <input type="email" id="email" name="email" required>

    <label for="message">Message</label>
    <textarea id="message" name="message"
              rows="5" placeholder="Your message..."></textarea>

    <button type="submit">Send Message</button>

</form>

Input Types

input_types.html
<input type="text">        <!-- plain text -->
<input type="email">       <!-- validates email format -->
<input type="password">    <!-- masked input -->
<input type="number" min="0" max="100">
<input type="range" min="0" max="10">
<input type="date">         <!-- date picker -->
<input type="color">        <!-- colour picker -->
<input type="file" accept=".pdf,.jpg">
<input type="checkbox">    <!-- toggle -->
<input type="radio" name="choice">
<input type="search">       <!-- search field -->
<input type="url">          <!-- validates URL -->
<input type="hidden" value="csrf-token">

<!-- Select dropdown -->
<select name="country">
    <option value="">Choose country</option>
    <optgroup label="Europe">
        <option value="gb">United Kingdom</option>
        <option value="de">Germany</option>
    </optgroup>
</select>

HTML5 Form Validation

validation.html
<input type="text" required>                    <!-- must be filled -->
<input type="text" minlength="3" maxlength="50"> <!-- length limits -->
<input type="number" min="18" max="120">         <!-- range -->
<input type="text" pattern="[A-Z]{3}-\d{4}">    <!-- regex pattern -->
<input type="text" readonly>                   <!-- can't be changed -->
<input type="text" disabled>                   <!-- greyed out -->
✅ Always use <label>
Every input must have an associated <label> — either wrapping the input, or connected via matching for and id attributes. This is critical for accessibility and click targets.
🎯 Exercise 7.1 — Contact Form

Build a complete contact form with: name, email, phone (optional), subject dropdown, message textarea, and a newsletter checkbox. Add HTML5 validation to required fields. Group related fields with <fieldset> and <legend>.

Lecture 08 · Core Concepts

Semantic HTML

Intermediate ~55 min Requires: Lecture 07

What is Semantic HTML?

Semantic HTML means using elements that convey meaning about the content they contain — not just how it looks. Compare these two identical-looking results:

non-semantic vs semantic
<!-- ❌ Non-semantic: divs everywhere -->
<div class="header">...</div>
<div class="nav">...</div>
<div class="main">
    <div class="article">...</div>
    <div class="sidebar">...</div>
</div>
<div class="footer">...</div>

<!-- ✅ Semantic: meaningful elements -->
<header>...</header>
<nav>...</nav>
<main>
    <article>...</article>
    <aside>...</aside>
</main>
<footer>...</footer>

HTML5 Semantic Elements

Element Purpose
<header> Page or section header (logo, nav, title)
<nav> Navigation links
<main> Primary unique content (one per page)
<article> Self-contained content (blog post, news item)
<section> Thematic grouping of content
<aside> Sidebar, related content
<footer> Footer (copyright, links, contact)
<figure> Self-contained figure (image, chart, code)
<figcaption> Caption for a figure
<time> Dates and times (machine-readable)
<address> Contact info for nearest article/body
<details> / <summary> Accordion/disclosure widget

A Full Page Layout

layout.html
<body>
  <header>
    <a href="/"><img src="logo.svg" alt="Site Logo"></a>
    <nav>
      <ul>
        <li><a href="/blog">Blog</a></li>
        <li><a href="/about">About</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <header>  <!-- article can have its own header -->
        <h1>Article Title</h1>
        <time datetime="2026-03-01">March 1, 2026</time>
      </header>
      <section>
        <h2>Introduction</h2>
        <p>Article content...</p>
      </section>
    </article>

    <aside>
      <h2>Related Posts</h2>
      <ul>...</ul>
    </aside>
  </main>

  <footer>
    <p>&copy; 2026 My Site</p>
    <address>
      Contact: <a href="mailto:hi@example.com">hi@example.com</a>
    </address>
  </footer>
</body>
🎯 Exercise 8.1 — Semantic Blog Post

Rebuild a page you made in a previous exercise using only semantic HTML5 elements. No <div> unless absolutely necessary. Include <header>, <main>, <article>, <aside>, <footer>, and at least one <time> element.

Lecture 09 · Advanced

HTML5 APIs & Features

Intermediate ~60 min Requires: Lecture 08

data-* Attributes

Custom data-* attributes let you embed extra information in HTML elements without using non-standard attributes or hidden inputs.

data-attributes.html
<button
    data-user-id="42"
    data-action="delete"
    data-confirm="true"
    class="btn-danger">
    Delete User
</button>

<!-- Access in JavaScript -->
<script>
const btn = document.querySelector('.btn-danger');
console.log(btn.dataset.userId);   // "42"
console.log(btn.dataset.action);    // "delete"
</script>

The <template> Element

template.html
<!-- Content inside <template> is parsed but NOT rendered -->
<template id="card-template">
    <div class="card">
        <h3 class="card-title"></h3>
        <p class="card-body"></p>
    </div>
</template>

<script>
    const tmpl  = document.getElementById('card-template');
    const clone = tmpl.content.cloneNode(true);
    clone.querySelector('.card-title').textContent = 'My Card';
    document.body.appendChild(clone);
</script>

The <dialog> Element

dialog.html
<dialog id="my-modal">
    <h2>Confirm Action</h2>
    <p>Are you sure you want to proceed?</p>
    <button id="close">Close</button>
</dialog>

<button id="open">Open Modal</button>

<script>
    const modal = document.getElementById('my-modal');
    document.getElementById('open').addEventListener('click', () => modal.showModal());
    document.getElementById('close').addEventListener('click', () => modal.close());
</script>

Other Useful HTML5 Features

html5_misc.html
<!-- Details / Summary accordion -->
<details>
    <summary>Click to expand</summary>
    <p>Hidden content revealed on click!</p>
</details>

<!-- Progress bar -->
<progress value="70" max="100">70%</progress>

<!-- Meter (gauge) -->
<meter value="0.7" min="0" max="1" low="0.25" high="0.75">70%</meter>

<!-- Datalist (autocomplete suggestions) -->
<input list="browsers" placeholder="Choose browser...">
<datalist id="browsers">
    <option value="Chrome">
    <option value="Firefox">
    <option value="Safari">
</datalist>

<!-- Canvas (JavaScript drawing surface) -->
<canvas id="myCanvas" width="400" height="200"></canvas>
🎯 Exercise 9.1 — Interactive Components

Build a page featuring: a <details> FAQ section (at least 3 questions), a <dialog> modal triggered by a button, a <datalist> search input, and a <progress> bar updated by a slider input using JavaScript.

Lecture 10 · Advanced

Accessibility (a11y)

Intermediate ~60 min Requires: Lecture 09

Why Accessibility Matters

Over 1 billion people worldwide have some form of disability. Web accessibility ensures your content is usable by everyone — including people using screen readers, keyboard-only navigation, or assistive devices. It's also legally required in many jurisdictions.

ℹ️ WCAG
The Web Content Accessibility Guidelines (WCAG) are the international standard. Aim for WCAG 2.1 Level AA compliance as a minimum.

ARIA Attributes

ARIA (Accessible Rich Internet Applications) attributes add semantic meaning where native HTML can't.

aria.html
<!-- Roles -->
<div role="alert">Error: Please fill in all fields.</div>
<div role="progressbar" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100">

<!-- Labels -->
<button aria-label="Close dialog"></button>
<nav aria-label="Breadcrumb">...</nav>

<!-- States -->
<button aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" aria-hidden="true">...</ul>

<!-- Describedby -->
<input type="password" aria-describedby="pw-hint">
<p id="pw-hint">Must be at least 8 characters.</p>

<!-- Live regions -->
<div aria-live="polite">Dynamic content announced here</div>

Keyboard Navigation

keyboard.html
<!-- Skip navigation link (first item on page) -->
<a href="#main-content" class="skip-link">Skip to main content</a>

<!-- tabindex: -1 removes from tab order; 0 adds to natural order -->
<div tabindex="0" role="button">Custom focusable element</div>
<div tabindex="-1">Programmatically focusable only</div>

<!-- Focus indicator - never remove outline without replacement! -->
<!-- In CSS: :focus-visible { outline: 2px solid #005fcc; } -->

Accessibility Checklist

Rule Why
All images have meaningful alt Screen readers describe images via alt text
Every input has a <label> Screen readers announce what the input is for
Colour contrast ≥ 4.5:1 Readable for low-vision / colour-blind users
Focus visible on all interactive elements Keyboard users need to see where they are
Use semantic headings in order (h1→h2→h3) Screen reader users navigate by headings
Don't rely on colour alone to convey info Colourblind users can't distinguish colour-only cues
Videos have captions Deaf users can still follow content
🎯 Exercise 10.1 — Accessibility Audit

Take a page you built earlier. Run it through the WAVE Accessibility Checker (wave.webaim.org). Fix any errors. Add ARIA labels to your navigation and buttons. Ensure all form inputs have labels. Test keyboard-only navigation.

Lecture 11 · Advanced

SEO & Meta Tags

Intermediate ~50 min Requires: Lecture 10

Essential Meta Tags

meta_seo.html
<head>
    <!-- Required -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Page Title — Brand Name</title>

    <!-- SEO Essentials -->
    <meta name="description"
          content="A 150-160 char description for Google search snippets.">
    <meta name="robots" content="index, follow">
    <link rel="canonical" href="https://example.com/this-page">

    <!-- Open Graph (social media previews) -->
    <meta property="og:type"        content="website">
    <meta property="og:title"       content="Page Title">
    <meta property="og:description" content="Description for social shares">
    <meta property="og:image"       content="https://example.com/og-image.jpg">
    <meta property="og:url"         content="https://example.com/this-page">

    <!-- Twitter Card -->
    <meta name="twitter:card"        content="summary_large_image">
    <meta name="twitter:site"        content="@yourhandle">

    <!-- Favicon -->
    <link rel="icon" href="/favicon.ico">
    <link rel="apple-touch-icon" href="/apple-touch-icon.png">
</head>

Structured Data (JSON-LD)

Structured data helps Google understand your content and create rich results (star ratings, breadcrumbs, FAQs, etc.).

jsonld.html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Introduction to HTML",
  "author": {
    "@type": "Person",
    "name": "Jane Smith"
  },
  "datePublished": "2026-03-01",
  "image": "https://example.com/article.jpg"
}
</script>

HTML Performance Tips

Technique How Impact
Lazy load images loading="lazy" Faster initial load
Async/defer scripts script defer Unblocks HTML parsing
Preload key resources <link rel="preload"> Prioritises critical assets
Preconnect to origins <link rel="preconnect"> Faster 3rd party resources
Specify image dimensions width height attrs Prevents layout shift (CLS)
Use WebP/AVIF images Modern formats Smaller file sizes
🎯 Exercise 11.1 — Full Head Section

Write a complete <head> section for a recipe website's article page. Include all essential meta tags, Open Graph tags for social sharing (with a real OG image URL), a JSON-LD Recipe schema, and resource hints (preconnect, preload).

Lecture 12 · Capstone

Capstone Project: Personal Portfolio

Advanced ~90 min Requires: All Lectures

Congratulations on reaching the final lecture! We'll now build a fully semantic, accessible, SEO-optimised personal portfolio website — a single HTML file that applies every concept from this course.

Project Features

Complete Portfolio HTML

portfolio/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jane Smith — Front-End Developer</title>
    <meta name="description" content="Jane Smith is a front-end developer based in London, specialising in accessible, performant web experiences.">
    <meta property="og:title" content="Jane Smith — Front-End Developer">
    <meta property="og:image" content="https://janesmith.dev/og.jpg">
    <link rel="canonical" href="https://janesmith.dev">
    <link rel="stylesheet" href="style.css">
    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "Person",
      "name": "Jane Smith",
      "jobTitle": "Front-End Developer",
      "url": "https://janesmith.dev",
      "sameAs": ["https://github.com/janesmith"]
    }
    </script>
</head>
<body>

<!-- Skip link -->
<a href="#main" class="skip-link">Skip to main content</a>

<header>
    <a href="/" aria-label="Jane Smith — Home">JS</a>
    <nav aria-label="Main navigation">
        <ul role="list">
            <li><a href="#about">About</a></li>
            <li><a href="#projects">Projects</a></li>
            <li><a href="#contact">Contact</a></li>
        </ul>
    </nav>
</header>

<main id="main">

    <!-- HERO SECTION -->
    <section aria-labelledby="hero-heading">
        <h1 id="hero-heading">Hi, I'm Jane Smith 👋</h1>
        <p>Front-End Developer building fast, accessible web experiences.</p>
        <a href="#projects">See my work</a>
        <a href="resume.pdf" download>Download CV</a>
    </section>

    <!-- ABOUT -->
    <section id="about" aria-labelledby="about-heading">
        <h2 id="about-heading">About Me</h2>
        <figure>
            <img src="jane.jpg"
                 srcset="jane-400.jpg 400w, jane-800.jpg 800w"
                 sizes="(max-width: 600px) 200px, 300px"
                 alt="Jane Smith smiling in a bright office"
                 width="300" height="300">
        </figure>
        <p>I'm a developer with 5 years of experience...</p>
    </section>

    <!-- PROJECTS -->
    <section id="projects" aria-labelledby="projects-heading">
        <h2 id="projects-heading">Projects</h2>
        <ul role="list">
            <li>
                <article>
                    <h3>Project Alpha</h3>
                    <p>A web app built with...</p>
                    <a href="https://github.com/..."
                       target="_blank" rel="noopener noreferrer"
                       aria-label="View Project Alpha on GitHub">View on GitHub</a>
                </article>
            </li>
        </ul>
    </section>

    <!-- CONTACT FORM -->
    <section id="contact" aria-labelledby="contact-heading">
        <h2 id="contact-heading">Get In Touch</h2>
        <form action="/contact" method="POST">
            <label for="name">Name <span aria-hidden="true">*</span></label>
            <input type="text" id="name" name="name"
                   autocomplete="name" required
                   aria-required="true">
            <label for="email">Email</label>
            <input type="email" id="email" name="email"
                   autocomplete="email" required>
            <label for="message">Message</label>
            <textarea id="message" name="message"
                      rows="5" required></textarea>
            <button type="submit">Send Message</button>
        </form>
    </section>

</main>

<footer>
    <p>&copy; <time datetime="2026">2026</time> Jane Smith</p>
    <address>
        <a href="mailto:jane@janesmith.dev">jane@janesmith.dev</a>
    </address>
</footer>

</body>
</html>

What You've Learned

This capstone project applied every major concept from the course:

🚀 What's Next?

You've completed the HTML curriculum! The natural next steps are:

  • CSS — Style your HTML with Flexbox, Grid, animations
  • JavaScript — Add interactivity and DOM manipulation
  • CSS Frameworks — Tailwind CSS, Bootstrap
  • Version Control — Git and GitHub
  • Deployment — Netlify, GitHub Pages, Vercel
  • Developer Tools — Chrome DevTools mastery
🎯 Final Challenge — Polish Your Portfolio

Extend the portfolio with: (1) a skills section using a <table> showing proficiency levels with <meter> elements, (2) a timeline of your experience using <ol> with <time> tags, (3) a working FAQ section using <details>/<summary>, (4) validate the final HTML at validator.w3.org with zero errors.