What is HTML?
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
- 1991 — Tim Berners-Lee publishes the first HTML spec (18 tags)
- 1995 — HTML 2.0: first formal standard
- 1997 — HTML 4.01: widespread adoption
- 2014 — HTML5 becomes the W3C standard (current)
- Today — HTML is a "living standard" maintained by WHATWG
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.
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.
<!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>
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:
Self-closing (void) elements
Some elements have no content and don't need a closing tag. These are called void elements:
<br> <!-- line break --> <hr> <!-- horizontal rule --> <img src="photo.jpg"> <!-- image --> <input type="text"> <!-- form input --> <meta charset="UTF-8">
HTML Comments
<!-- 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> -->
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.
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).
Document Structure
The HTML Boilerplate
Every valid HTML5 document follows the same fundamental structure. Understanding each part is essential before writing any real content.
<!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
<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> 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 |
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.
Text & Typography
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.
<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>
Main Page Title (use once)
Section Heading
Sub-section
Paragraphs & Line Breaks
<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
<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>
Bold / important Italic / emphasis
Highlighted Strikethrough
H2O and E = mc2 inline code Ctrl+C
A long quoted passage from another source.
<strong> over <b> and <em> over
<i>. Semantic tags convey meaning, not just appearance — crucial for screen
readers and SEO.
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.
Links & Navigation
The Anchor Tag
The <a> (anchor) element creates hyperlinks. The href attribute specifies
the destination.
<!-- 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>
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 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 |
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.
Images & Media
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.
<!-- 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
<!-- 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>
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.
Lists & Tables
Unordered Lists
<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> <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>
| Month | Revenue | Growth |
|---|---|---|
| January | $12,400 | +8% |
| February | Data unavailable | |
| Total | $12,400 | — |
Create a table of your favourite films: title, year, director, genre. Include proper
<thead>, <tbody>, <caption>, and
scope attributes on <th> elements.
Forms & Inputs
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 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 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
<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 -->
<label> — either wrapping the input, or connected
via matching for and id attributes. This is critical for accessibility and
click targets.
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>.
Semantic HTML
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: 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
<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>© 2026 My Site</p> <address> Contact: <a href="mailto:hi@example.com">hi@example.com</a> </address> </footer> </body>
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.
HTML5 APIs & Features
data-* Attributes
Custom data-* attributes let you embed extra information in HTML elements without using
non-standard attributes or hidden inputs.
<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
<!-- 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 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
<!-- 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>
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.
Accessibility (a11y)
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.
ARIA Attributes
ARIA (Accessible Rich Internet Applications) attributes add semantic meaning where native HTML can't.
<!-- 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
<!-- 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 |
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.
SEO & Meta Tags
Essential Meta Tags
<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.).
<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 |
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).
Capstone Project: Personal Portfolio
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
- Fully semantic HTML5 structure (header, nav, main, sections, footer)
- Responsive images with
srcset - A working contact form with HTML5 validation
- ARIA attributes throughout
- Complete SEO head with Open Graph tags
- JSON-LD
Personstructured data - Skills table, project cards, and a timeline
Complete Portfolio 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>© <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:
- Document structure — valid boilerplate, proper head
- Text & typography — headings, paragraphs, inline elements
- Links — navigation, anchor links, external links with security attributes
- Images — srcset, alt text, figure/figcaption
- Lists & tables — semantic markup, scoped headers
- Forms — inputs, labels, validation, autocomplete
- Semantic HTML — header, nav, main, section, article, aside, footer
- Accessibility — ARIA, skip links, focus management
- SEO & meta — Open Graph, JSON-LD, canonical
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
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.