learn-html-with-phoebe / Session 3 of 6
Learn HTML with Phoebe · Session 3 of 6

Pictures and structure: media plus semantic layout

Two upgrades today. First your page gets a face: images, video, and audio, done the honest way with alt text and captions. Then it gets a spine: the semantic regions (header, nav, main, footer) that turn a pile of headings into a page machines and humans can navigate.

🟡 Moderate Total beginners welcome Data & AI folks too 45 min live + self-study depth
0-3 · Welcome 3-23 · Concepts (live cards) 23-40 · Three demos 40-45 · Q&A
Part 0

Why this session exists

After Session 2 your page has real words, working links, and a finished head. But it is still a text file that looks like one, and under the hood it is one long body with no map. Today it gets media (Part 1 and 2) and a semantic skeleton (Part 3) - the same landmark structure every professional site and every screen reader relies on.

Live - presented in session Self-study - read after class ★ Try it now Every example on this page is editable - type and watch
★ What you walk out with today The img element with the alt discipline pros use, figure and figcaption for images that explain themselves, the video and audio pattern with graceful fallbacks, and a project page wrapped in header, nav, main, and footer - plus your own photo on it, served from a proper images folder. The orange panels are live: edit the left, the right re-renders.
Part 1 · covers MDN "Images in HTML" + web.dev "Images"

Images done right 8 min live

One void element, four attributes, and a habit of honesty. The img element is easy to use and easy to use badly - the difference is almost entirely in the alt text and in telling the browser the image's size up front.

Liveimg - src, alt, width, height3 min▶

<img> is a void element (no content, no closing tag - Session 1) that is all attributes: src says which file, alt says what it shows, width and height declare its natural size in pixels so the browser reserves the space before the file arrives. Skip the size and the page jumps around while loading - the layout shift you feel on janky news sites.

One void element, four attributes reserve the shape THE MARKUP THE RESERVED SPACE <img src="picsum.photos/300/200" alt="Placeholder landscape photo" width="300" height="200"> 300 × 200 px reserved before load fails to load → shows: "Placeholder photo" src says which file, alt is the fallback, width and height reserve the box before it loads.
🔍 Click to zoom - width and height stop the page from jumping while the file loads
<p>A photo, politely announced:</p>
<img src="https://picsum.photos/300/200"
     alt="Placeholder landscape photo from the picsum service"
     width="300" height="200">
  • The demo URL is a placeholder service - picsum.photos returns a random photo at the size you ask for. Handy for layouts; your real page uses your real files.
  • Width and height set the real ratio; making images respond to screen size is a CSS job (Session 5), and serving different files to different screens (srcset) is a deep dive for 6.3.
LiveThe alt discipline - describe function, not filename2 min▶

The alt attribute is what a screen reader speaks, what renders if the file fails, and what search engines index. The test: if the image vanished, what words would do its job? Describe what it means in context, never what the file is called.

✗ alt="image of a chart" Screen reader announces the filename. Search engines index nothing useful. Image vanishes, so does the point. ✓ alt: names the finding alt="Line chart: accuracy 71% to 94%" Screen reader speaks the real finding. Image vanishes - the sentence survives. The test: if the image vanished, what words would do its job? That's honest alt text.
🔍 Click to zoom - honest alt text is what survives when the picture doesn't load
Weak altalt="IMG_4032.jpg" or alt="photo" or alt="image of a chart" - a screen-reader user hears filename noise and learns nothing.
Honest altalt="Line chart: model accuracy climbing from 71% to 94% over ten training runs" - the image could vanish and the point survives.
  • Decorative images get alt="" - empty, but present. That tells screen readers "skip me, I am decoration". Omitting alt entirely makes them read the filename aloud instead.
  • Never start with "image of" - the screen reader already announces it is an image.
Real world

Data folks: alt text is your chart's caption for machines. Dashboards and reports get emailed, and email clients block images by default - the alt text is often the only thing stakeholders see on first open. A one-line summary of the finding beats a broken-image icon every time.

Livefigure and figcaption - images that explain themselves2 min▶

When an image needs a visible caption, wrap both in <figure> and put the caption in <figcaption>. The browser now knows the caption belongs to the image - they travel together, and assistive tech announces them as one unit. Note the two are different jobs: alt describes the image, the caption comments on it.

<figure>
  <img src="https://picsum.photos/400/220"
       alt="Placeholder photo standing in for a project screenshot"
       width="400" height="220">
  <figcaption>Fig 1 - the caption travels with the image.</figcaption>
</figure>

Figure is not only for images: a code block, a chart, or a table with a caption are all figures. If it could move to an appendix and still make sense with its caption, it is a figure.

Self-studyWhere files live, which format, and whose picture it is3 min read▶

Three housekeeping habits that separate tidy sites from junk drawers:

  • An images/ subfolder. Inside my-site, next to index.html, make a folder called images and keep every picture there. The src is then a relative path, exactly like the link paths from Session 2: src="images/me.jpg".
  • Lowercase, no spaces in filenames: phoebe-portrait.jpg, never My Photo (1).JPG. Servers are case-sensitive and spaces break URLs.
FormatOne-line rule
.jpgPhotos - small files, no transparency, slight quality loss.
.pngScreenshots and images needing transparency - lossless, bigger files.
.webpThe modern all-rounder - smaller than both, supported everywhere that matters.
.svgLogos, icons, diagrams - drawn from text, sharp at any size (the diagrams on this page are SVG).
Licensing honesty Found on Google is not free to use. Safe sources: photos you took, images you made, and openly licensed libraries (Unsplash, Pexels, Wikimedia Commons - check each license). Credit the creator when the license asks. Your page is public from Session 6 - build the habit now.
Part 2 · covers MDN "Video and audio content" + web.dev "Audio and Video"

Audio and video - media with manners 5 min live

The video and audio elements follow the img mental model, with two upgrades: they can offer the browser several file formats to choose from, and they hold fallback content for the rare browser that understands neither.

Livevideo - controls, source elements, fallback3 min▶

The pattern: a <video> element with controls (never autoplay a visitor's speakers), a poster image to show before play, one or more <source> children listing formats from best to safest, and plain fallback content at the bottom. The browser plays the first source it supports and shows the fallback only if it supports none.

<video controls width="320" height="180"
       poster="images/intro-poster.jpg">
  <source src="images/intro.webm" type="video/webm">
  <source src="images/intro.mp4" type="video/mp4">
  Your browser does not play video.
  <a href="images/intro.mp4">Download the file instead.</a>
</video>
  • controls is a boolean attribute - present means on, no value needed. It gives you play, pause, volume, and fullscreen for free.
  • poster is the cover image before play - without it, visitors stare at a black rectangle.
  • Captions: real published video should carry a <track> element pointing at a captions file. We mark it honest-incomplete today (◐) - the pattern is one line, writing good captions is the real work.
Liveaudio - the same idea, minus the picture2 min▶

<audio> works exactly like video without width, height, or poster. Same controls attribute, same source-and-fallback pattern.

<p>Episode 1 of my someday-podcast:</p>
<audio controls src="audio/episode-1.mp3">
  Your browser does not play audio.
</audio>
Real world

This is the exact markup behind podcast pages, voice-note features, and every "listen to this article" button. And the multi-source pattern is a data lesson in disguise: ship formats in preference order, let the client pick the first one it can handle - the same graceful-degradation thinking as good API design.

Part 3 · covers MDN "Structuring documents" + web.dev "Semantic HTML"

Semantic layout - give the page a map 7 min live

So far everything sits loose in the body. Semantic layout elements wrap your content in named regions - landmarks that screen readers jump between, search engines weigh, and future-you navigates. Same page, now with a map legend.

<header> your name + the nav - the banner visitors see first <nav> the list of links that steer the page <main> the unique content - exactly one per page <section id="about"> <section id="projects"> <section id="contact"> <aside> related but not the point - side notes, "now reading", optional <footer> small print - copyright, contact, "built by hand" These are landmarks: screen-reader users jump straight between them, skipping everything else.
🔍 Click to zoom - the classic page map. Every region is a real element wrapping your existing content.
Liveheader, nav, main, footer - the big four3 min▶
  • <header> - the introduction strip: your name (the h1) and the nav. Not to be confused with the invisible <head> from Session 1 - header is visible content.
  • <nav> - wraps your list of links from Session 2. The wrapper is what lets assistive tech announce "navigation" and offer to skip it.
  • <main> - the unique content of this page. The one hard rule of the day: exactly one main per page, and it never holds the header or footer.
  • <footer> - the sign-off: copyright line, contact, small print.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Phoebe Fu</title>
  </head>
  <body>
    <header>
      <h1>Phoebe Fu</h1>
      <nav>
        <ul>
          <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>
      <section id="about">
        <h2>About</h2>
        <p>Data and AI person, building a corner of the internet.</p>
      </section>
      <section id="projects">
        <h2>Projects</h2>
        <p>Things shipped and things brewing.</p>
      </section>
      <section id="contact">
        <h2>Contact</h2>
        <p>Say hello.</p>
      </section>
    </main>
    <footer>
      <p>Built by hand, one session at a time.</p>
    </footer>
  </body>
</html>
Livesection vs article vs div - the decision rules3 min▶

Three wrappers, three questions, asked in order:

  • Would it make sense on its own, somewhere else? A blog post, a product card, a project entry that could appear in a feed - that is an <article>. Self-contained is the test.
  • Is it a themed chunk of this page, deserving its own heading? About, Projects, Contact - that is a <section>. A section without a heading is usually a section that should not exist.
  • Neither - you just need a box to style or group? That is a <div>. No meaning, no shame; it is the honest choice when no semantic element fits.

And <aside> is for content related to, but separable from, the main flow: a "currently reading" box, a related-links list. Nesting is normal: articles inside sections, sections inside articles - the questions above decide each layer.

When in doubt Ask "would a screen-reader user want to jump to this?" Yes: pick the semantic element. No: div. Wrong semantics is worse than no semantics - a page of ten navs is noise, not structure.
Self-studydiv, span, and the outline nuances2 min read▶

<div> is the meaningless block, <span> its inline sibling - a way to grab a few words inside a sentence, which becomes gold in Session 5 when classes and CSS arrive. Reach for them last, not first.

One nuance from web.dev's "Headings and sections" worth knowing: browsers do not build a real document outline from nested sections - your h1-h6 ladder from Session 1 is still what defines the outline. So keep the ladder honest inside your regions: one h1 in the header, h2 per section. Regions are the map, headings are the index.

Demo 1 of 3 · the running project grows a spine

Wrap your page in regions ★ 8 min · follow along

Your index.html has content and a nav list. Nothing new gets written today - the existing content gets wrapped in the four regions, and the page becomes navigable by machine.

Open your index.html. Wrap your h1 and the nav list from Session 2 in a <header> element.

Wrap everything between the header and the bottom of the page in a single <main>. One per page - this is it.

Inside main, wrap each h2 block in a <section> and move the id from the heading onto the section: <section id="about">, <section id="projects">, <section id="contact">. Your anchor links keep working - ids are ids.

After main, add a <footer> with one honest paragraph: your name, the year, how to reach you.

Save, reload, and observe: the page looks identical. That is correct - semantics change what the page IS, not how it looks. Session 5 pays this off when regions become styling hooks.

Indentation check You just added three levels of nesting. Re-indent so each level steps in two spaces - thirty seconds now, or a headache every session after.
Demo 2 of 3

Your photo, honestly captioned ★ 5 min · build your own

The page gets a face - yours, or anything that represents you. This is the moment the images/ folder is born.

Create an images folder next to your index.html. Drop in a photo, renamed to something clean: me.jpg or phoebe-portrait.jpg. Lowercase, no spaces.

In your About section, add the image: <img src="images/me.jpg" alt="..." width="..." height="...">. Get the real pixel size from your file manager's info panel.

Write the alt like a pro: what would a visitor need to know if the photo never loaded? "Phoebe smiling on a mountain trail" beats "photo of me".

Wrap it in a <figure> and add a <figcaption> with a visible one-liner. Save, reload - if you see a broken icon, check the path and the filename spelling first, exactly like Session 2's link debugging.

Real world

Relative paths bite here the same way they bite in notebooks: src="images/me.jpg" means "from where THIS file sits". Move index.html without moving the folder and the image breaks - the same reason your pandas read_csv("data/file.csv") breaks when you run the notebook from a different directory.

Demo 3 of 3

The landmark tour ★ 4 min · follow along

See your page the way a screen reader sees it. Devtools has an accessibility view that renders the landmark structure you just built - proof that semantics are real, not ceremony.

On your page, right-click anywhere and choose Inspect. In devtools, find the Accessibility panel (Chrome: it is a tab near Styles; Firefox: its own top-level tab).

Look at the accessibility tree: your header appears as banner, nav as navigation, main as main, footer as contentinfo. Those are the landmarks a screen-reader user jumps between.

Now inspect a plain div on any other site and compare: no landmark, no name, invisible to the tour. That is the difference you built today.

Find your image in the tree and confirm your alt text is what it announces. If you used alt="" anywhere, watch that image vanish from the tree entirely - as designed.

Homework

Try it yourself - this week ◐ 30-45 min total

Source material

Official sources covered

This session teaches the working content of these lessons from MDN's Structuring content with HTML and web.dev Learn HTML. Their interactive challenges stay with the originals - our exercises are equivalents, not copies.

✓MDN: Images in HTMLPart 1 - img, alt discipline, figure/figcaption, formats, licensing
✓MDN: Video and audio contentPart 2 - controls, source fallback chain, poster
✓MDN: Structuring documentsPart 3 + Demo 1 - header, nav, main, section/article/aside, footer
✓web.dev: Semantic HTML + Headings and sectionsPart 3 - landmark thinking; outline nuance in self-study
✓web.dev: Images + Audio and VideoParts 1-2 - shared core taught once
◐Responsive images (srcset, sizes, picture)named today; deep dive 6.3 goes pro
◐track element + captions filespattern shown; writing real captions is the deep end
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · A purely decorative divider image sits between two sections. The right alt is...

Empty alt tells screen readers to skip decoration. Describing it adds noise; omitting alt entirely makes some readers announce the filename instead.

2 · Each project entry on your page could also appear on its own in a portfolio feed. The best wrapper is...

Self-contained is the article test. Section is for themed chunks of THIS page; div is for when no meaning applies at all.

3 · How many main elements may a page have?

One main per page - it marks THE unique content. Screen readers offer "skip to main content" and there must be one unambiguous answer.

Session 3 cheat sheet · pin this

img essentials<img src="images/me.jpg" alt="..." width="300" height="200">. Void element. Size attributes stop layout jumping.
The alt disciplineDescribe function in context, never the filename. Decorative: alt="" (empty, present). Never start with "image of".
figure + figcaptionWrap image and visible caption together. Alt describes, caption comments - two different jobs.
File housekeepingimages/ subfolder, lowercase filenames, no spaces. src is a relative path from the HTML file's location.
Formatsjpg photos · png screenshots/transparency · webp modern all-rounder · svg logos and diagrams.
Media patternvideo/audio + controls, source elements best-to-safest, plain fallback content last. poster = video cover image.
The region mapheader (h1 + nav) → main (sections) → footer. Exactly one main per page. aside = related but separable.
section vs article vs divSelf-contained elsewhere = article. Themed chunk with heading = section. Just a styling box = div, no shame.