# HTML From Zero

> HTML is the structure underneath every web page - the tags that say 'this is a heading, this is a link, this is a list.' Build a real About Me page from an empty skeleton to a fully semantic document.


---

# HTML From Zero

You know HTML, CSS, and JavaScript have separate jobs - HTML for structure, CSS for looks, JavaScript for
behavior. Now it's time to actually write some. This guide teaches HTML by building one real page: a personal
"About Me" page, starting from nothing and ending with a complete, semantic document.

Every phase adds to the same file. By the end you'll have a page with a heading, a bio, a photo, a list of
skills, links to your other profiles, and proper document structure - and you'll understand why each tag is
the right one for the job.

## How to read this

- **New to HTML?** Read in order. Phase 1 gives you the skeleton every page needs, phase 2 fills it with
  content, phase 3 makes it semantic and complete.
- **Know some HTML already?** Skip to [Phase 3: Semantic HTML and Document Structure](03-semantic-html-and-document-structure.md)
  for `<header>`/`<main>`/`<footer>` and why they beat `<div>` soup.

## The phases

1. **[Your First Page: Elements, Tags, and Structure](01-your-first-page-elements-tags-and-structure.md)** -
   what a tag, element, and attribute actually are, the doctype and the `<html>`/`<head>`/`<body>` skeleton,
   nesting rules, and void elements like `<br>` and `<img>`.
2. **[Text, Lists, Links, and Images](02-text-lists-links-and-images.md)** - headings, paragraphs, semantic
   emphasis with `<strong>`/`<em>`, lists, links, and images with real `alt` text.
3. **[Semantic HTML and Document Structure](03-semantic-html-and-document-structure.md)** - `<header>`,
   `<nav>`, `<main>`, `<section>`, `<footer>` instead of generic `<div>`s, why it matters for screen readers
   and search engines, and the finished, annotated About Me page.

> This guide stops at structure. It doesn't touch colors, fonts, or layout - that's
> [CSS Without Tears](/guides/css-without-tears), linked again at the end once you have something worth
> styling.


---

# Your First Page: Elements, Tags, and Structure

Open a plain text file, save it as `about.html`, and you've started writing HTML. There's no compiler, no
build step - a browser reads the text and decides how to show it based on the tags you put in it. That's the
whole game: tags tell the browser what each piece of content *is*, and the browser figures out how to display it.

## Tags, elements, and attributes

A **tag** is the marker itself, wrapped in angle brackets: `<p>`. Most tags come in pairs - an opening tag
and a closing tag with a `/`:

```html
<p>This is a paragraph.</p>
```

The opening tag, the content, and the closing tag together are called an **element**. So `<p>` is a tag, but
`<p>This is a paragraph.</p>` is an element. People say "tag" for both loosely, but when you see "element" in
docs, it means the whole package.

Tags can carry extra information called **attributes**, written inside the opening tag as `name="value"`:

```html
<a href="https://example.com">Visit example.com</a>
```

Here `href` is an attribute telling the `<a>` (link) element where to go. Attributes always live in the
opening tag, never the closing one, and their values go in quotes.

## Nesting: elements live inside elements

Elements can contain other elements, not just text:

```html
<p>My favorite language is <strong>Rust</strong>.</p>
```

`<strong>Rust</strong>` is nested inside the `<p>`. The rule is simple: whatever you open last, you close
first - like folding boxes inside boxes. This is valid:

```html
<p><strong>Bold text</strong></p>
```

This is not, because the tags cross over each other:

```html
<p><strong>Bold text</p></strong>
```

Browsers often render broken nesting anyway by guessing what you meant, which is exactly the problem - the
guess isn't always right, and it's a habit that bites you in bigger pages. Close tags in the reverse order
you opened them.

## Void elements: tags with no closing pair and no content

Some tags represent something that has no inner content to wrap around, so they never get a closing tag.
These are called **void elements**. The two you'll use constantly:

```html
<br>
<img src="photo.jpg" alt="A photo of me">
```

`<br>` forces a line break - there's nothing to put "inside" a line break, so it's just `<br>`, not
`<br></br>`. `<img>` embeds an image via its `src` attribute - the image data itself lives in a separate
file, not between tags, so there's no content to close around either. Other common void elements: `<hr>`
(a horizontal rule), `<input>`, `<meta>`, `<link>`.

⚠️ **Gotcha:** writing `<img src="photo.jpg"></img>` isn't wrong enough to break most pages, but it's
nonstandard and some tools will flag it. Void elements don't get a separate closing tag.

## The skeleton every HTML page needs

Every page starts with the same four pieces, in the same order:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>About Me</title>
  </head>
  <body>

  </body>
</html>
```

Here's what each one does:

- **`<!DOCTYPE html>`** - not a tag, a declaration. It tells the browser "render this as modern HTML," so it
  doesn't fall back to a decades-old compatibility mode. Always the first line, always exactly this.
- **`<html>`** - the root element. Every other tag lives inside it.
- **`<head>`** - metadata about the page: the tab title, character encoding, links to CSS files. Nothing in
  `<head>` shows up as visible page content.
- **`<body>`** - everything the visitor actually sees: text, images, links, buttons, all of it.

📝 **Terminology:** the `<title>` element (inside `<head>`) sets the text shown in the browser tab. People
often mistake it for a visible page heading - it isn't one. Visible headings come from `<h1>`-`<h6>`, covered
next phase.

## Building the About Me skeleton

Save this as `about.html`:

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>About Me</title>
  </head>
  <body>

  </body>
</html>
```

The `<meta charset="UTF-8">` line tells the browser how to decode the text - which characters map to which
bytes. Without it, accented letters, curly quotes, or emoji can render as garbled symbols. It's a void
element, same family as `<br>`. Add it right after `<head>` opens; every real page has one.

Open the file in a browser and you'll see a blank page with "About Me" in the tab. That blank `<body>` is
where the next phase starts filling in content.

Check your understanding of tags, elements, and the skeleton:

```quiz
[
  {
    "q": "What's the difference between a tag and an element?",
    "choices": [
      "They're the same thing, just different names",
      "A tag is the marker like <p>; an element is the opening tag, content, and closing tag together",
      "An element is only used in the head; a tag is only used in the body",
      "A tag has attributes; an element never does"
    ],
    "answer": 1,
    "explain": "A tag is the bracketed marker itself. An element is the full package: opening tag, content, closing tag."
  },
  {
    "q": "Why does <img> not have a closing tag?",
    "choices": [
      "It's a mistake that browsers tolerate",
      "It's a void element - there's no inner content for a closing tag to wrap around",
      "Only tags inside <head> need closing tags",
      "Older HTML versions required it, but modern HTML dropped it"
    ],
    "answer": 1,
    "explain": "Void elements like <img> and <br> represent something with no content to nest inside, so they never get a separate closing tag."
  },
  {
    "q": "Where does visible page content - text, images, links - go?",
    "choices": [
      "Inside <head>",
      "Inside <title>",
      "Inside <body>",
      "Directly inside <!DOCTYPE html>"
    ],
    "answer": 2,
    "explain": "<head> holds metadata that never displays. Everything a visitor actually sees lives inside <body>."
  }
]
```


---

# Text, Lists, Links, and Images

The About Me page has a skeleton but nothing in it. Time to fill `<body>` with the tags that carry almost all
written content on the web: headings, paragraphs, emphasis, lists, links, and images.

## Headings: one `<h1>`, then step down

Headings come in six levels, `<h1>` through `<h6>`, biggest and most important to smallest:

```html
<h1>Alex Rivera</h1>
<h2>About Me</h2>
<h3>Background</h3>
```

`<h1>` is the page's main title - use it exactly **once** per page. Levels below it should nest by
importance, not by how big you want text to look: `<h2>` for major sections, `<h3>` for subsections inside
those. Screen readers let users jump heading-to-heading like a table of contents, so skipping from `<h1>`
straight to `<h4>` because it "looked right" breaks that navigation for them.

⚠️ **Gotcha:** don't pick a heading level for its default font size. `<h3>` looks small because browsers
style it small by default, not because it means "less important than h1." Size is CSS's job - covered in
[CSS Without Tears](/guides/css-without-tears). Pick heading levels by document structure.

## Paragraphs: the default text container

```html
<p>I'm a backend developer who spends most days in Rust and most evenings figuring out why my houseplants keep dying.</p>
```

`<p>` is a block of text - a paragraph. Browsers add space above and below it automatically. Don't use empty
`<p></p>` tags or a chain of `<br>` elements to fake spacing between paragraphs; each real paragraph gets its
own `<p>`.

## Semantic emphasis vs. visual styling

`<strong>` and `<em>` mark text as *important* or *stressed* - they are not shortcuts for "bold" and
"italic." That distinction matters more than it looks:

```html
<p><strong>Warning:</strong> this bio contains puns.</p>
<p>I <em>genuinely</em> love debugging race conditions.</p>
```

Browsers happen to render `<strong>` as bold and `<em>` as italic by default, which is why people confuse
them with styling tags. But a screen reader changes its *tone of voice* for `<strong>` and `<em>` - it
doesn't do that for text that's merely bold via CSS. If you want text bold purely for looks, with no added
meaning, that's a CSS job (`font-weight`), not an HTML one. Reach for `<strong>`/`<em>` when the emphasis is
part of the meaning; reach for CSS when it's purely decorative.

💡 **Key point:** HTML says what something *is* (important, emphasized, a heading). CSS says what it *looks
like*. Mixing the two up is the single most common HTML habit to unlearn.

## Lists: unordered, ordered, and their items

Two list types, both built from `<li>` (list item) elements:

```html
<h3>Skills</h3>
<ul>
  <li>Rust</li>
  <li>PostgreSQL</li>
  <li>Debugging things at 2am</li>
</ul>

<h3>How I Got Here</h3>
<ol>
  <li>Learned Python in college</li>
  <li>Got hooked on backend systems</li>
  <li>Switched to Rust and never looked back</li>
</ol>
```

`<ul>` (unordered list) is for items where order doesn't matter - bullets. `<ol>` (ordered list) is for
sequence - numbers. Every `<li>` must live directly inside a `<ul>` or `<ol>`; it doesn't work on its own.

## Links: `<a href>`

```html
<a href="https://github.com/alexrivera">My GitHub</a>
```

`<a>` (anchor) creates a link. The `href` attribute is where it points - a full URL, or a relative path to
another page on the same site (`about.html`). Text between the tags is what's clickable. Opening a link in a
new tab needs `target="_blank"`:

```html
<a href="https://github.com/alexrivera" target="_blank">My GitHub</a>
```

## Images: `<img src alt>`, and why `alt` isn't optional

```html
<img src="alex-headshot.jpg" alt="Alex Rivera smiling, standing in front of a bookshelf">
```

`src` points at the image file. `alt` is a text description of the image - and it's doing three jobs at
once, not one:

- **Screen readers read it aloud** instead of the image, for anyone who can't see the picture.
- **It shows in place of the image** if the file fails to load or is slow on a bad connection.
- **Search engines use it** to understand what the image contains, since they can't "see" it either.

Skipping `alt` doesn't just look sloppy - it silently excludes anyone using a screen reader from that part of
the page. Skip the description only for purely decorative images (`alt=""`, deliberately empty), never omit
the attribute entirely. This guide only scratches the surface - the full picture is in
[Accessibility From Day One](/guides/accessibility-from-day-one).

## Putting it in the About Me page

Here's `<body>` filled in:

```html
<body>
  <h1>Alex Rivera</h1>
  <img src="alex-headshot.jpg" alt="Alex Rivera smiling, standing in front of a bookshelf">

  <h2>About Me</h2>
  <p>I'm a backend developer who spends most days in <strong>Rust</strong> and most evenings figuring out why my houseplants keep dying.</p>

  <h2>Skills</h2>
  <ul>
    <li>Rust</li>
    <li>PostgreSQL</li>
    <li>Debugging things at 2am</li>
  </ul>

  <h2>Find Me Online</h2>
  <ul>
    <li><a href="https://github.com/alexrivera" target="_blank">GitHub</a></li>
    <li><a href="https://alexrivera.dev" target="_blank">Portfolio</a></li>
  </ul>
</body>
```

Load it in a browser: one big title, a photo with a real description, a bio with one emphasized word, a
bullet list of skills, and clickable links. Every tag here describes what something *is* - that's the whole
skill of HTML.

Check what you just learned:

```quiz
[
  {
    "q": "How many <h1> elements should a page have?",
    "choices": ["As many as you want", "Exactly one", "Zero - h1 is deprecated", "One per section"],
    "answer": 1,
    "explain": "h1 marks the page's main title. Screen readers and search engines rely on there being exactly one to identify the page's primary heading."
  },
  {
    "q": "You want text bold purely for visual style, with no added meaning. What should you use?",
    "choices": ["<strong>", "<b> with CSS font-weight, or CSS alone", "<em>", "A heading tag"],
    "answer": 1,
    "explain": "<strong> and <em> signal semantic importance/emphasis - screen readers change tone for them. Purely visual boldness belongs to CSS, not a semantic tag."
  },
  {
    "q": "Why does an <img> need an alt attribute?",
    "choices": [
      "It's only for search engine ranking",
      "It's optional decoration with no real function",
      "Screen readers read it aloud, it shows if the image fails to load, and search engines use it to understand the image",
      "It only matters for images inside <ul> lists"
    ],
    "answer": 2,
    "explain": "alt text serves accessibility, fallback display, and search indexing all at once - skipping it excludes screen reader users from that content."
  }
]
```


---

# Semantic HTML and Document Structure

The About Me page works, but everything sits loose in `<body>` - a browser has no idea which part is the
page header, which part is the main content, and which part is a footer. `<div>` could technically wrap any
of it, but `<div>` means nothing on its own. This phase replaces that ambiguity with tags that describe
structure, not just group things visually.

## The problem with `<div>` soup

```html
<div class="header">
  <div class="title">Alex Rivera</div>
</div>
<div class="content">
  <div class="bio">I'm a backend developer...</div>
</div>
<div class="footer">© 2026 Alex Rivera</div>
```

This renders fine. But a `<div>` is a generic box - it carries zero meaning about what's inside it. The only
reason a human knows `class="header"` is the header is the class name; a screen reader or search engine
doesn't parse your class names for intent. Nest enough of these and you get "div soup": structurally
identical boxes stacked arbitrarily, readable only by squinting at CSS classes.

## Semantic elements: tags that say what they are

HTML has purpose-built tags for the sections almost every page has:

```html
<header>...</header>
<nav>...</nav>
<main>...</main>
<section>...</section>
<article>...</article>
<footer>...</footer>
```

- **`<header>`** - introductory content for the page or a section: a title, a logo, a tagline.
- **`<nav>`** - a block of navigation links.
- **`<main>`** - the primary content of the page. Use it once per page.
- **`<section>`** - a thematic grouping of content, usually with its own heading.
- **`<article>`** - a self-contained piece that would make sense on its own if pulled out and syndicated
  elsewhere (a blog post, a single skill card).
- **`<footer>`** - closing content: copyright, contact info, closing links.

These render exactly like `<div>` by default - no visual difference. The difference is entirely in the
meaning they carry.

## Why semantics matter: two audiences who can't see your CSS classes

**Screen readers.** A screen reader builds a navigable outline of a page from tags like `<header>`, `<nav>`,
and `<main>`. A blind user can jump straight to "main content," skipping repeated navigation on every page
load. That skip is only possible if the page uses real `<nav>` and `<main>` elements - a `<div class="nav">`
is invisible to that navigation feature. Full detail lives in
[Accessibility From Day One](/guides/accessibility-from-day-one).

**Search engines.** Crawlers weight content inside `<main>` and `<article>` differently than content inside
`<nav>` or `<footer>`, because those tags tell it what's actually the point of the page versus what's
boilerplate repeated everywhere. Semantic structure is free signal you'd otherwise have to fight for.

💡 **Key point:** `<div>` groups things for styling. Semantic tags group things by *meaning*. Use semantic
tags first; drop down to `<div>` only when no semantic tag fits (a generic styling wrapper with no
structural meaning of its own).

## The finished, annotated About Me page

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>About Me</title>
  </head>
  <body>

    <header>
      <h1>Alex Rivera</h1>
      <img src="alex-headshot.jpg" alt="Alex Rivera smiling, standing in front of a bookshelf">
    </header>

    <nav>
      <ul>
        <li><a href="#about">About</a></li>
        <li><a href="#skills">Skills</a></li>
        <li><a href="#links">Find Me Online</a></li>
      </ul>
    </nav>

    <main>
      <section id="about">
        <h2>About Me</h2>
        <p>I'm a backend developer who spends most days in <strong>Rust</strong> and most evenings figuring out why my houseplants keep dying.</p>
      </section>

      <section id="skills">
        <h2>Skills</h2>
        <ul>
          <li>Rust</li>
          <li>PostgreSQL</li>
          <li>Debugging things at 2am</li>
        </ul>
      </section>

      <section id="links">
        <h2>Find Me Online</h2>
        <ul>
          <li><a href="https://github.com/alexrivera" target="_blank">GitHub</a></li>
          <li><a href="https://alexrivera.dev" target="_blank">Portfolio</a></li>
        </ul>
      </section>
    </main>

    <footer>
      <p>&copy; 2026 Alex Rivera</p>
    </footer>

  </body>
</html>
```

Walking through the structure:

- **`<header>`** holds the name and photo - introductory, not the main point of the page.
- **`<nav>`** wraps a plain `<ul>` of links. Semantic tags still use ordinary tags inside them; `<nav>` just
  tells the browser "this list is for navigating," on top of "this is a list."
- **`<main>`** wraps everything that's actually the content - one per page, never nested inside another
  `<main>`.
- **`<section>`** breaks `<main>` into three thematic chunks, each with its own `<h2>` and an `id` the nav
  links jump to.
- **`<footer>`** closes the page with copyright - content that's true regardless of which section someone
  scrolled to.

The visible result hasn't changed from phase 2. What changed is that the page's structure is now readable by
machines, not just implied by which order things happen to appear on screen.

## Where to go next

The About Me page is complete: structured, filled with content, and marked up semantically. It also looks
exactly as plain as the very first skeleton - browser default fonts, no color, no layout. That's next:
[CSS Without Tears](/guides/css-without-tears) takes this exact page and makes it look like something.

Last check before you move on:

```quiz
[
  {
    "q": "What's the main problem with building a page entirely out of <div> elements?",
    "choices": [
      "Divs render slower than semantic tags",
      "Divs carry no meaning about what the content is, only CSS classes do - which screen readers and crawlers don't read for intent",
      "Divs can't contain headings",
      "Browsers no longer support <div>"
    ],
    "answer": 1,
    "explain": "A <div> is a generic box. Its meaning exists only in a class name a human wrote - assistive tech and search engines can't infer intent from that the way they can from <nav> or <main>."
  },
  {
    "q": "How many <main> elements should a page have?",
    "choices": ["As many as there are sections", "Exactly one", "One per <article>", "Zero - main is optional decoration"],
    "answer": 1,
    "explain": "<main> marks the primary content of the page. One per page lets screen reader users jump straight to it, skipping repeated navigation."
  },
  {
    "q": "Visually, how does <section> differ from <div> in a browser with no CSS applied?",
    "choices": [
      "It doesn't - both render as an unstyled block by default; the difference is semantic meaning",
      "<section> is bold by default",
      "<section> adds a border automatically",
      "<section> centers its content"
    ],
    "answer": 0,
    "explain": "Semantic tags look identical to <div> with no CSS - the entire benefit is machine-readable meaning, not appearance."
  }
]
```
