HTML Fundamentals
Introduction
HTML (HyperText Markup Language) is the backbone of every web page. It provides the structure and meaning to your content. This article covers everything you need to know to write semantic, accessible HTML5.
What You'll Learn
- HTML document structure
- Semantic elements and when to use them
- Text content and headings
- Links, images, and media
- Forms and input validation
- Accessibility best practices
HTML Document Structure
Every HTML document follows a standard structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title</title>
<meta name="description" content="Page description">
</head>
<body>
<!-- Page content goes here -->
</body>
</html>
Element Breakdown
| Element | Purpose | Required? |
|---|---|---|
<!DOCTYPE html> |
Tells browser to use HTML5 mode | Yes |
<html> |
Root element of the document | Yes |
lang="en" |
Specifies document language | Recommended |
<head> |
Contains metadata (not visible) | Yes |
<meta charset> |
Character encoding (UTF-8) | Yes |
<title> |
Page title (shown in tabs) | Yes |
<body> |
Contains visible page content | Yes |
Semantic Elements
Semantic HTML describes the meaning of content, not just its appearance. This helps search engines, screen readers, and developers understand your page structure.
┌─────────────────────────────────────────────┐
│ <header> │
│ ┌─────────┐ ┌─────────────────┐ │
│ │ Logo │ │ <nav> │ │
│ └─────────┘ └─────────────────┘ │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ <main> │
│ ┌───────────────────────────────────────┐ │
│ │ <article> │ │
│ │ <h1>Article Title</h1> │ │
│ │ <p>Content...</p> │ │
│ │ </article> │ │
│ └───────────────────────────────────────┘ │
│ ┌───────────────────────────────────────┐ │
│ │ <aside> │ │
│ │ Related content / Sidebar │ │
│ │ </aside> │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ <footer> │
│ Copyright | Links | Contact Info │
└─────────────────────────────────────────────┘
Common Semantic Elements
| Element | Purpose | Example Use |
|---|---|---|
<header> |
Introductory content | Site header, article header |
<nav> |
Navigation links | Main menu, breadcrumbs |
<main> |
Primary content | Page's main content (one per page) |
<article> |
Self-contained content | Blog post, news story, comment |
<section> |
Thematic grouping | Chapter, tab content |
<aside> |
Related but separate | Sidebar, callout box |
<footer> |
Closing content | Site footer, article footer |
Complete Semantic Page Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Blog - Home</title>
</head>
<body>
<header>
<h1>My Blog</h1>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/contact/">Contact</a></li>
</ul>
</nav>
</header>
<main>
<article>
<header>
<h2>My First Post</h2>
<time datetime="2026-03-01">March 1, 2026</time>
</header>
<p>Welcome to my blog!</p>
</article>
</main>
<footer>
<p>© 2026 My Blog</p>
</footer>
</body>
</html>
Text Content & Headings
HTML provides various elements for structuring text content:
<h1>Main Page Title (one per page)</h1>
<h2>Section Heading</h2>
<h3>Subsection Heading</h3>
<h4>Sub-subsection Heading</h4>
<h5>Minor Heading</h5>
<h6>Smallest Heading</h6>
<p>This is a paragraph of text.</p>
<p>This paragraph has <strong>strong importance</strong>
and <em>emphasized text</em>.</p>
<ul>
<li>Unordered list item</li>
<li>Another item</li>
</ul>
<ol>
<li>First ordered item</li>
<li>Second ordered item</li>
</ol>
<blockquote>
<p>This is a block quotation.</p>
<cite>— Author Name</cite>
</blockquote>
<code>inline code</code>
<pre>
<code>
def hello():
print("Hello, World!")
</code>
</pre>
Heading Best Practices
- Use one
<h1>per page (main title) - Don't skip heading levels (h1 → h2 → h3, not h1 → h4)
- Headings should describe content structure
- Don't use headings just for styling (use CSS instead)
Links & Navigation
The <a> (anchor) element creates hyperlinks:
<!-- Internal link -->
<a href="/about/">About Us</a>
<!-- External link -->
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
External Site
</a>
<!-- Email link -->
<a href="mailto:[email protected]">Email Us</a>
<!-- Phone link -->
<a href="tel:+1234567890">Call Us</a>
<!-- Download link -->
<a href="/file.pdf" download>Download PDF</a>
<!-- Link with title (tooltip) -->
<a href="/docs/" title="Read our documentation">
Documentation
</a>
Link Attributes
| Attribute | Purpose | Example |
|---|---|---|
href |
Destination URL | href="/page/" |
target |
Where to open link | target="_blank" |
rel |
Relationship to linked page | rel="noopener noreferrer" |
download |
Download instead of navigate | download="file.pdf" |
Images & Media
Embed images, audio, and video in your pages:
<!-- Basic image -->
<img src="photo.jpg" alt="Description of image">
<!-- Responsive image -->
<img
src="photo-small.jpg"
srcset="photo-small.jpg 480w, photo-medium.jpg 768w, photo-large.jpg 1200w"
sizes="(max-width: 600px) 480px, (max-width: 900px) 768px, 1200px"
alt="Description"
>
<!-- Figure with caption -->
<figure>
<img src="chart.png" alt="Sales chart showing growth">
<figcaption>Q1 2026 Sales Results</figcaption>
</figure>
<!-- Video with controls -->
<video controls poster="thumbnail.jpg">
<source src="video.mp4" type="video/mp4">
<source src="video.webm" type="video/webm">
<track src="subtitles.vtt" kind="subtitles" srclang="en">
Your browser doesn't support video.
</video>
<!-- Audio player -->
<audio controls>
<source src="audio.mp3" type="audio/mpeg">
Your browser doesn't support audio.
</audio>
Image Best Practices
- Always include
alt- Required for accessibility - Use descriptive alt text - Describe the image's purpose
- Decorative images - Use
alt=""(empty) - Responsive images - Use
srcsetfor different screen sizes - Lazy loading - Add
loading="lazy"for below-fold images
Forms & Input Validation
Forms collect user input. HTML5 provides built-in validation:
<form action="/submit" method="POST">
<!-- Text input -->
<label for="name">Name:</label>
<input
type="text"
id="name"
name="name"
required
minlength="2"
maxlength="50"
placeholder="Enter your name"
>
<!-- Email input -->
<label for="email">Email:</label>
<input
type="email"
id="email"
name="email"
required
placeholder="[email protected]"
>
<!-- Password -->
<label for="password">Password:</label>
<input
type="password"
id="password"
name="password"
required
minlength="8"
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
title="Must contain number, lowercase, uppercase, 8+ chars"
>
<!-- Number input -->
<label for="age">Age:</label>
<input
type="number"
id="age"
name="age"
min="18"
max="120"
>
<!-- Select dropdown -->
<label for="country">Country:</label>
<select id="country" name="country" required>
<option value="">Select...</option>
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
<option value="ca">Canada</option>
</select>
<!-- Radio buttons -->
<fieldset>
<legend>Gender:</legend>
<label>
<input type="radio" name="gender" value="male">
Male
</label>
<label>
<input type="radio" name="gender" value="female">
Female
</label>
</fieldset>
<!-- Checkbox -->
<label>
<input type="checkbox" name="terms" required>
I agree to the terms
</label>
<!-- Textarea -->
<label for="message">Message:</label>
<textarea
id="message"
name="message"
rows="5"
required
></textarea>
<!-- Submit button -->
<button type="submit">Submit</button>
</form>
Input Types
| Type | Purpose | Validation |
|---|---|---|
text |
Single-line text | minlength, maxlength, pattern |
email |
Email address | Email format validation |
password |
Password (hidden) | minlength, pattern |
number |
Numeric input | min, max, step |
tel |
Phone number | pattern |
url |
URL | URL format validation |
date |
Date picker | min, max |
Accessibility Fundamentals
Make your HTML accessible to all users, including those using screen readers:
<!-- Skip link for keyboard users -->
<a href="#main" class="skip-link">Skip to main content</a>
<!-- Landmark regions -->
<header role="banner">...</header>
<nav role="navigation" aria-label="Main">...</nav>
<main id="main" role="main">...</main>
<footer role="contentinfo">...</footer>
<!-- Form labels (required) -->
<label for="email">Email:</label>
<input type="email" id="email" name="email">
<!-- ARIA for dynamic content -->
<div aria-live="polite" aria-atomic="true">
Status messages appear here
</div>
<!-- Button with icon -->
<button aria-label="Close dialog">
<span aria-hidden="true">×</span>
</button>
<!-- Image alternatives -->
<img src="logo.png" alt="Company Name Logo">
<img src="decoration.png" alt=""> <!-- Decorative -->
WCAG Quick Reference
| Principle | Requirement | HTML Solution |
|---|---|---|
| Perceivable | Alt text for images | alt="description" |
| Operable | Keyboard accessible | Use <button>, <a> |
| Understandable | Clear labels | <label for="id"> |
| Robust | Valid HTML | Use W3C validator |
Key Takeaways
- Use semantic elements to describe content meaning
- Include one
<h1>per page - Always provide
alttext for images - Use
<label>for all form inputs - Implement accessibility from the start
- Validate your HTML with the W3C Validator
FAQ
What's the difference between <div> and <span>?
<div> is a block-level element (starts on new line). <span> is inline (flows with text). Neither has semantic meaning—use semantic elements when possible.
When should I use <section> vs <article>?
Use <article> for self-contained content (blog post, comment). Use <section> for thematic groupings within a page.
Do I need to close all HTML tags?
Most tags should be closed, but some are self-closing: <img>, <input>, <br>, <hr>, <meta>, <link>.
What's the purpose of the lang attribute?
It tells browsers and screen readers what language the content is in, enabling proper pronunciation and hyphenation.
Next Steps
Now that you understand HTML structure, learn how to style it with CSS: