Python · SQL · Web Dev · Java · AI/ML tracks launching soon — your one platform for all of IT
Beginner+200 XP

Semantic HTML & Accessibility Basics

Why semantics matter beyond styling — ARIA basics, accessible forms, and how screen readers and search engines actually read your page.

40 min August 2026
// Part 01 — Beyond Convenience

Why Semantic Tags Matter — For More Than Just Tidy Code

By this point in the track you have already used <header>, <nav>, <main>, <section>, <article>, <aside>, and <footer> — semantic tags that describe what a piece of content is, not just how it should look. It is tempting to think of the difference between these and a generic <div> as purely stylistic — after all, a <nav> and a <div class="nav"> can be made to look pixel-identical with CSS. This module is about the part of the story that has nothing to do with appearance at all: semantic tags are read directly by software other than a rendering engine — screen readers, browser extensions, search engine crawlers, and browser built-in features like Reader Mode — and each of those depends on the tag actually being correct, not merely styled to look correct.

Visually identical, structurally very different
<!-- Version A — looks fine, means nothing to assistive technology -->
<div class="nav">
  <div class="nav-item"><a href="/">Home</a></div>
  <div class="nav-item"><a href="/about">About</a></div>
</div>

<!-- Version B — identical appearance with the right CSS, but this
     is machine-readable structure, not just visual grouping -->
<nav>
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
  </ul>
</nav>

Both versions render identically once styled. The difference only becomes visible the moment something other than a sighted user with a mouse tries to use the page — which, across a real, large user base, is a meaningfully large fraction of visitors, and is also legally significant in many jurisdictions (covered further in Part 07).

💡 Note
A useful mental model for the rest of this module: CSS controls how a page looks. Semantic HTML controls what a page is, structurally, independent of any stylesheet. A page with all CSS removed should still make structural sense when read top to bottom — that is precisely the experience a screen reader user, and a search engine crawler, actually has.
// Part 02 — Landmark Navigation

How Screen Readers Actually Use Landmark Navigation

Semantic elements like <header>, <nav>, <main>, <aside>, and <footer> are called landmarks in accessibility terminology. Screen readers (VoiceOver on macOS/iOS, NVDA and JAWS on Windows, TalkBack on Android) build a navigable list of every landmark on the page, and expose a dedicated keyboard shortcut that lets a user jump directly between them — without needing to listen to every single line of content in between.

What a screen reader's landmark list looks like for a well-structured page
<header>...</header>       →  Landmark: "banner"
<nav>...</nav>             →  Landmark: "navigation"
<main>                     →  Landmark: "main"
  <article>...</article>   →  Landmark: "article"
  <aside>...</aside>       →  Landmark: "complementary"
</main>
<footer>...</footer>       →  Landmark: "content info"

<!-- A VoiceOver or NVDA user can press a single key combination to
     jump straight from "banner" to "main", skipping the entire
     navigation menu — every single time, on every page that uses this
     structure, without the site author writing a single line of extra code. -->

This is precisely the accessibility equivalent of a sighted user visually scanning a page and immediately recognizing "that block at the top is the header, that block down there is the footer" without reading every word — landmarks give a non-visual user the exact same fast, skippable structure, but only if the underlying tags are the correct semantic ones rather than generic <div>s.

The "skip to main content" link — landmark navigation's visible cousin

A related, very common pattern is a "Skip to main content" link placed as the very first focusable element on the page, visually hidden until it receives keyboard focus. This exists for keyboard-only users (not necessarily screen reader users — someone using a keyboard due to a motor impairment, or simply preference, benefits from this too) who would otherwise need to tab through an entire navigation menu on every single page before reaching the actual content.

A skip link, hidden until focused
<body>
  <a href="#main-content" class="skip-link">Skip to main content</a>
  <header>...</header>
  <nav>...</nav>
  <main id="main-content">
    ...
  </main>
</body>

<style>
  .skip-link {
    position: absolute;
    top: -40px;      /* off-screen by default */
    left: 0;
    background: #000;
    color: #fff;
    padding: 8px 16px;
    z-index: 100;
  }
  .skip-link:focus {
    top: 0;           /* snaps into view the instant it receives keyboard focus */
  }
</style>

A <main> landmark with an id serves as this link's target, which is one more reason a page should have exactly one <main> — multiple instances confuse both this pattern and the landmark-jumping behavior described above.

// Part 03 — ARIA Roles

Basic ARIA Roles — For When Semantic HTML Alone Isn't Enough

ARIA (Accessible Rich Internet Applications) is a set of attributes that add accessibility information HTML cannot express on its own — most often needed for custom interactive widgets that have no native HTML equivalent, like a tab panel, a modal dialog, or a custom dropdown built from <div>s and JavaScript rather than a native <select>. The single most important rule of ARIA, stated in the official spec itself, is worth internalizing before anything else:

⚠️ Important
The First Rule of ARIA: if a native HTML element or attribute already has the semantics and behavior you need, use it instead of re-purposing an element and adding ARIA to make it accessible. A <button> is already keyboard-focusable, already announces itself as "button" to a screen reader, and already responds to Enter and Space — none of that has to be reconstructed with ARIA. ARIA should be reached for only when no native element covers the pattern you need, not as a default habit.
role — overriding what an element is announced as
<!-- A custom-built tab interface, made of divs, needs explicit roles
     since <div> carries no semantic meaning of its own -->
<div role="tablist">
  <div role="tab" aria-selected="true">Overview</div>
  <div role="tab" aria-selected="false">Reviews</div>
  <div role="tab" aria-selected="false">Shipping</div>
</div>
<div role="tabpanel">
  Overview content goes here...
</div>

Common roles you will genuinely see in production codebases include role="alert" (for content that should be announced immediately, like a form validation error), role="dialog" (for a modal), and role="button" — the last of which is almost always a code smell, since it usually means a <div> or <span> is being made to behave like a button with JavaScript, when a real <button> would have needed no role at all.

An alert region for validation errors
<div role="alert" id="form-error">
  Please enter a valid email address.
</div>

<!-- role="alert" causes screen readers to announce this text
     IMMEDIATELY when it appears in the DOM, without the user
     needing to navigate to it manually — appropriate specifically
     for urgent, time-sensitive messages like this one. -->
🎯 Pro Tip
Many implicit ARIA roles already exist on native HTML elements without you writing anything — <nav> already has an implicit role of navigation, <button> already has an implicit role of button. Explicit role attributes exist to cover the gap where no native element fits, not to duplicate what semantic HTML already provides for free.
// Part 04 — aria-label and Friends

aria-label, aria-labelledby, and aria-describedby

aria-label provides an accessible name for an element directly, as a string, overriding whatever text content the element would otherwise be announced with. It is most commonly needed on icon-only buttons — a trash-can icon with no visible text has nothing for a screen reader to announce unless something explicitly supplies a name.

aria-label on an icon-only button
<!-- Without aria-label, a screen reader announces this as
     just "button" — completely unhelpful -->
<button>
  <svg><!-- trash can icon --></svg>
</button>

<!-- With aria-label, it announces as "Delete item, button" -->
<button aria-label="Delete item">
  <svg><!-- trash can icon --></svg>
</button>

aria-labelledby — pointing to existing visible text instead of duplicating it

When the accessible name should come from text that is already visible elsewhere on the page, aria-labelledby references that element's id rather than repeating the string — useful because it keeps a single source of truth; if the visible text changes, the accessible name updates automatically along with it.

aria-labelledby referencing an existing heading
<h2 id="billing-heading">Billing Information</h2>
<section aria-labelledby="billing-heading">
  <!-- This section is announced as "Billing Information" without
       repeating that string anywhere in an aria-label -->
  ...
</section>

aria-describedby — supplementary description, not a replacement name

aria-describedby is subtly different — it adds extra descriptive text after an element's accessible name is announced, rather than replacing that name. It is the standard pattern for connecting a form field to its own helper text or error message.

Connecting a password field to its requirements
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-hint">
<p id="password-hint">Must be at least 12 characters, with one number.</p>

<!-- A screen reader announces: "Password, edit text, protected.
     Must be at least 12 characters, with one number." -->
💡 Note
None of these three attributes change anything visually — that is precisely the point. They exist entirely for the accessibility tree, the parallel structure browsers build specifically for screen readers and other assistive technology, invisible to sighted users but exactly what a screen reader actually reads from.
// Part 05 — Writing Good Alt Text

Alt Text — What Actually Makes It Good or Bad

You met the alt attribute in the Images and Media module as a required attribute on every <img>. This module goes further: not every non-empty string is good alt text, and the difference between good and bad alt text is entirely about whether it conveys the same information or purpose the image conveys to a sighted user — not about literally describing every visual detail.

Bad alt text — several distinct failure modes
<!-- Failure 1: describes pixels, not purpose -->
<img src="chart.png" alt="a blue and orange bar chart">

<!-- Failure 2: redundant filler that adds no information -->
<img src="ceo.jpg" alt="image of the CEO">

<!-- Failure 3: keyword-stuffed for SEO, unreadable as a sentence -->
<img src="shoes.jpg" alt="running shoes sneakers athletic shoes buy shoes online cheap shoes">

<!-- Failure 4: empty when the image is actually meaningful content -->
<img src="warning-icon.png" alt="">
The same four images, with genuinely good alt text
<!-- Fix 1: describes what the chart actually communicates -->
<img src="chart.png" alt="Quarterly revenue grew 34% from Q1 to Q4 2025">

<!-- Fix 2: no filler — a screen reader already announces "image" itself -->
<img src="ceo.jpg" alt="Maria Chen, CEO of Norwell Robotics">

<!-- Fix 3: reads as a natural sentence, describing the actual product -->
<img src="shoes.jpg" alt="Men's blue running shoes with reflective trim">

<!-- Fix 4: a meaningful icon gets meaningful alt text, not an empty string -->
<img src="warning-icon.png" alt="Warning: this action cannot be undone">

Fix 2 demonstrates a rule worth calling out explicitly: never begin alt text with phrases like "image of" or "picture of." Screen readers already announce that the element is an image before reading the alt text itself, so prefixing it produces an announcement like "image, image of the CEO" — redundant, and a real, common mistake even among people who genuinely intend to write good alt text.

When alt="" is actually the correct choice — purely decorative images

Failure 4 above was wrong specifically because that icon was meaningful. A genuinely decorative image — a background flourish, a repeated visual divider that adds no information — should have alt="" (present, but empty) so a screen reader skips it entirely rather than interrupting the page's content with a description of something that carries no meaning. An empty alt is a deliberate, correct signal, not a shortcut or an oversight, and it is meaningfully different from omitting the alt attribute altogether — which some screen readers instead read aloud as the full image filename.

🎯 Pro Tip
A genuinely reliable test for alt text quality: read it aloud, on its own, with no image visible. If it sounds like a natural sentence a person would actually say to describe what that image means in context, it is probably good. If it sounds like a list of keywords, or a caption that only makes sense alongside the picture itself, it needs a rewrite.
// Part 06 — Accessible Forms Recap

Accessible Forms — Tying Back to the Forms Modules

The previous two modules covered form controls in depth without dwelling on accessibility specifically — this section closes that loop, connecting patterns you have already learned back to exactly why they matter for a non-sighted or keyboard-only user.

The single most important accessible-forms rule — every input needs a real, connected label
<!-- Inaccessible — placeholder is not a label, and disappears once typing starts -->
<input type="email" placeholder="Email address">

<!-- Accessible — a real <label>, connected via matching for/id -->
<label for="email">Email address</label>
<input type="email" id="email">

A screen reader announces a properly connected label the instant a user tabs into the field — "Email address, edit text." A placeholder-only input, once the user starts typing, leaves a screen reader user with genuinely no way to recall what the field was even for, since the placeholder text itself is never announced as a label at all in most screen readers, and disappears visually the moment there is real input.

The <fieldset>/<legend> pattern from the previous module is itself an accessibility feature, not just visual grouping — recall from Part 02 of that module that a screen reader announces the legend before every control nested inside, giving a user navigating a long form the same "which section am I in" context a sighted user gets for free from the visual box around the group. And the aria-describedby pattern from Part 04 of this module is precisely how you should connect a field to helper text or a validation error message — an error message that only appears in red text next to a field, with no aria-describedby connecting it, is entirely invisible to a screen reader user who has no way to know it exists.

A validation error, properly connected for screen readers too
<label for="email">Email address</label>
<input type="email" id="email" aria-describedby="email-error" aria-invalid="true">
<p id="email-error" role="alert">Please enter a valid email address.</p>

aria-invalid="true" additionally flags the field itself as currently failing validation, and role="alert" (from Part 03) ensures the error text is announced immediately rather than requiring the user to navigate to it manually.

// Part 07 — Why Div Soup Fails Real Users

"Div Soup" — Why It Fails Real Users, Not Just SEO

"Div soup" is the (somewhat derisive) term for markup built almost entirely out of <div> and <span>, with classes doing all the work that semantic tags should be doing. Most discussion of this problem focuses on search engine optimization — and it is true that search engines weight semantic structure when ranking pages — but that framing badly undersells the actual harm, which is to real people using real assistive technology, right now, regardless of how a page ranks in search results.

Div soup — every failure from this module, compounded in one snippet
<div class="header">
  <div class="logo">Acme Co</div>
  <div class="nav">
    <div class="nav-item" onclick="location.href='/'">Home</div>
    <div class="nav-item" onclick="location.href='/pricing'">Pricing</div>
  </div>
</div>
<div class="main">
  <div class="title">Welcome</div>
  <div class="button" onclick="submitForm()">Submit</div>
</div>

Walk through what a screen reader user actually experiences with this markup, point by point. There is no <header>, <nav>, or <main> landmark, so the "jump between sections" navigation from Part 02 has nothing to jump to — the entire page is one undifferentiated block of content that must be read start to finish. Every <div class="nav-item"> is announced as plain, unremarkable text, not as a link — because it is not a link; it is a div with an onclick handler, which is entirely invisible to keyboard navigation and to a screen reader's "list all the links on this page" feature. The <div class="title"> is not a heading, so it does not appear in the "jump between headings" navigation either, even though visually it clearly reads as one. And the <div class="button"> is not keyboard-focusable at all by default, meaning a keyboard-only user — again, not necessarily a screen reader user — cannot Tab to it or activate it with Enter or Space, full stop.

The same page, structurally correct — nothing about the visual design has to change
<header>
  <div class="logo">Acme Co</div>
  <nav>
    <a href="/">Home</a>
    <a href="/pricing">Pricing</a>
  </nav>
</header>
<main>
  <h1>Welcome</h1>
  <button type="submit">Submit</button>
</main>
⚠️ Important
Every one of these failures is entirely invisible in a normal visual review of the page. A designer, a product manager, and most manual QA testers looking at div soup rendered in a browser will see a perfectly normal-looking header, navigation, and button — the CSS makes all of it look correct. The failures only surface when the page is actually used with a keyboard alone, or with a screen reader, or audited with a tool like Lighthouse or axe — which is exactly why this class of bug survives so often into production: it passes every visual check while failing every real usage from the users it fails.

A further, less obvious cost: div soup with no semantic structure also produces a genuinely worse experience for Reader Mode (in Safari, Firefox, and Chrome), for browser translation features, and for any tool — including AI-driven ones — that tries to programmatically extract the "real" content of a page from its markup. Semantic structure is, in a real sense, an API your HTML exposes to every piece of software that isn't a human looking at rendered pixels.

// Part 08 — Real World
💼 What This Looks Like at Work

An Accessibility Audit at an Austin Healthcare Startup

Scenario — Healthcare startup, Austin · Pre-launch accessibility audit

A patient-portal startup is weeks from launch when a legal requirement surfaces: as a healthcare provider, the product must meet WCAG 2.1 AA accessibility standards, both because it is the right thing to do and because non-compliance carries real legal exposure under the ADA for a company handling patient data. An external accessibility auditor is brought in to review the appointment-booking flow before launch.

A fragment of the flagged appointment-booking page
<div class="page">
  <div class="topbar">
    <div class="logo">MedLink</div>
    <div class="menu-item" onclick="goTo('/appointments')">Appointments</div>
    <div class="menu-item" onclick="goTo('/messages')">Messages</div>
  </div>
  <div class="content">
    <div class="page-title">Book an Appointment</div>
    <div class="field">
      <input type="text" placeholder="Reason for visit">
    </div>
    <img src="doctor-photo.jpg">
    <div class="submit-btn" onclick="bookAppointment()">Confirm Booking</div>
  </div>
</div>

The audit's findings

The auditor's report reads almost like a checklist against this exact module. No landmarks (Part 02) — a screen reader user has no way to jump past the top bar to the actual booking content. Navigation built from div.menu-item with onclick instead of real <a> tags (Part 07) — completely unreachable by keyboard, and invisible to a screen reader's link list. A placeholder standing in for a real <label> on the reason-for-visit field (Part 06) — the field's purpose disappears the instant a patient starts typing. A missing alt attribute entirely on the doctor's photo, not even an empty one (Part 05) — most screen readers fall back to reading the raw filename, doctor-photo.jpg, aloud to the patient. And a div.submit-btn standing in for a real <button>, unreachable by keyboard entirely — meaning a keyboard-only user cannot complete a booking at all.

The rewritten fragment
<div class="page">
  <header>
    <div class="logo">MedLink</div>
    <nav>
      <a href="/appointments">Appointments</a>
      <a href="/messages">Messages</a>
    </nav>
  </header>
  <main>
    <h1>Book an Appointment</h1>
    <div class="field">
      <label for="reason">Reason for visit</label>
      <input type="text" id="reason" placeholder="e.g. Annual checkup">
    </div>
    <img src="doctor-photo.jpg" alt="Dr. Elena Ruiz, Family Medicine">
    <button type="submit">Confirm Booking</button>
  </main>
</div>

None of these fixes changed a single pixel of the rendered page — the CSS classes and visual design were untouched. The team ships on schedule, the audit is cleared, and the engineering lead adds an automated axe-core accessibility scan to the CI pipeline specifically so this exact class of issue is caught on every future pull request, not only at a pre-launch audit.

// Part 09 — Misconceptions

Four Misconceptions About Accessibility

✕ ""Accessibility is mainly about screen reader users, a small fraction of visitors""
Accessibility benefits keyboard-only users, users with motor impairments who cannot use a mouse precisely, users with low vision using browser zoom, and users with situational limitations (a broken arm, a bright-sunlight screen, a noisy environment where captions replace audio) — a genuinely broad and common set of real usage patterns, not a narrow edge case.
✕ ""You can bolt accessibility onto a div-soup page later with enough ARIA attributes""
ARIA can patch some gaps, but it cannot restore native keyboard behavior (Tab focus, Enter/Space activation) to a div — that has to be either the correct native element or a substantial amount of extra JavaScript reimplementing behavior the browser already gives you for free with the right tag. The First Rule of ARIA exists precisely because native elements are almost always the more complete, less error-prone solution.
✕ ""an empty alt attribute means an image is missing accessibility information — it should always have real descriptive text""
An empty alt is the CORRECT choice for genuinely decorative images — it tells a screen reader to skip the image entirely rather than interrupt the content with a description of something meaningless. It only becomes a bug when applied to an image that actually carries information, like an icon or a meaningful photo.
✕ ""Accessibility fixes generally require changing how a page looks""
Nearly every fix in this module — swapping a div for a nav, a button, or an h1, connecting a label with for/id, adding aria-label to an icon button — changes the underlying markup while leaving the rendered, styled appearance completely untouched, exactly as shown in the Real World example above.
// Part 10 — Interview Prep

6 Interview Questions — With Complete Answers

What is a landmark, and why does it matter for screen reader users specifically?
A landmark is a semantic region like header, nav, main, aside, or footer that a screen reader exposes in a dedicated navigable list, letting a user jump directly between major page regions with a keyboard shortcut instead of listening through every line of content in between. It gives non-visual users the same fast structural overview a sighted user gets for free by visually scanning the page layout.
What is the First Rule of ARIA, and why does it matter?
If a native HTML element already provides the semantics and behavior you need, use it instead of reconstructing that behavior on a generic element with ARIA attributes. Native elements come with correct keyboard behavior, focus handling, and screen reader announcements built in for free; recreating all of that manually with ARIA and JavaScript is more work and far more error-prone than simply using the right tag.
What is the functional difference between aria-label, aria-labelledby, and aria-describedby?
aria-label directly supplies an accessible name as a string. aria-labelledby supplies that name by referencing another element's id, useful when the name text is already visible on the page and should not be duplicated. aria-describedby is different in kind, not just mechanism — it adds supplementary description AFTER the accessible name is announced, rather than replacing the name, and is the standard way to connect a form field to helper text or an error message.
Why is a placeholder not an acceptable substitute for a real <label> on a form input?
A placeholder disappears visually the moment a user starts typing, so there is no persistent visual reminder of the field's purpose. More critically for accessibility, most screen readers do not announce placeholder text as a label at all when a user tabs into the field, meaning the field's purpose can be entirely unclear. A real <label> connected via matching for/id attributes is announced every time the field receives focus and remains visible regardless of the field's content.
What makes alt text good versus bad, beyond simply being present?
Good alt text conveys the same information or purpose the image conveys to a sighted user, phrased as a natural sentence, without prefixes like "image of" (redundant, since screen readers already announce the element as an image) and without keyword stuffing for SEO. For genuinely decorative images that carry no information, an empty alt="" is correct — it causes the image to be skipped entirely rather than announced with a meaningless description.
Why is div soup considered an accessibility problem and not just an SEO or code-quality problem?
Search engine ranking is one real cost, but the more direct harm is to actual users of assistive technology, right now: no landmarks means no jump-navigation, div-based "links" and "buttons" with onclick handlers are unreachable by keyboard and invisible to a screen reader's link/button list, and div-based "headings" do not appear in heading navigation. These failures are invisible in a normal sighted visual review since CSS can make a div look identical to the correct semantic element, which is exactly why they survive into production so often.
// Common Mistakes

Accessibility Mistakes Beginners Make Constantly

Using placeholder as the only label on a form field
Broken: <input type="email" placeholder="Email">. Fixed: <label for="email">Email</label><input type="email" id="email" placeholder="you@example.com"> — a real label plus an optional placeholder for a formatting hint, not a replacement for the label.
Building interactive controls out of div or span with onclick
Broken: <div class="btn" onclick="save()">Save</div> — invisible to keyboard navigation and screen reader button lists. Fixed: <button type="button" onclick="save()">Save</button> — free keyboard focus, Enter/Space activation, and correct screen reader announcement.
Writing alt text that describes pixels instead of meaning, or omitting alt entirely
Broken: <img src="q4-revenue.png"> (no alt at all — many screen readers fall back to reading the filename). Fixed: <img src="q4-revenue.png" alt="Q4 revenue grew 34% year over year">.
Reaching for ARIA before checking whether a native element already solves the problem
Broken: <div role="button" tabindex="0" onclick="submit()">Submit</div> — technically improves on a bare div, but still requires manually wiring up keyboard activation, which is easy to get subtly wrong (e.g. forgetting Space, not just Enter). Fixed: <button type="submit">Submit</button> — all of that behavior is already built in.
Skipping heading levels or using headings purely for visual size rather than structure
Broken: an h1 followed directly by an h4 because "it was the right visual size," with no h2 or h3 in between — this breaks the heading-based navigation screen reader users rely on. Fixed: use heading levels for genuine document structure (h1 → h2 → h3 in order) and control visual size with CSS font-size instead of picking a heading level for its default appearance.
// Error Library

Errors and Audit Failures You Will Hit With Accessibility

Lighthouse / axe: "Form elements must have labels"
Cause: An input has no associated <label>, no aria-label, and no aria-labelledby — a placeholder alone does not satisfy this check, since automated auditors correctly treat it as insufficient.
Fix: Add a real <label> connected via matching for/id attributes, or aria-label if a visible label is genuinely not appropriate for the design.
Lighthouse / axe: "Images must have alternate text"
Cause: An <img> element has no alt attribute at all. This is different from having an empty alt="" — a missing attribute entirely fails this specific check, while an intentionally empty one for a decorative image passes it.
Fix: Add an alt attribute to every image — a real description for meaningful images, or alt="" for purely decorative ones.
Lighthouse / axe: "Buttons must have discernible text"
Cause: A <button> contains only an icon (an SVG or icon font glyph) with no text content and no aria-label, leaving it with no accessible name at all for a screen reader to announce.
Fix: Add aria-label="..." describing the button's action, or include visually-hidden text inside the button for the same purpose.
Lighthouse / axe: "Heading levels should only increase by one"
Cause: A heading skips a level, e.g. an h1 followed directly by an h3 with no h2 — usually caused by choosing heading tags based on their default visual size rather than genuine document structure.
Fix: Reorder headings to increase by exactly one level at a time, and use CSS to control visual appearance independent of the semantic heading level chosen.
Screen reader announces a raw filename instead of a description
Cause: An image is missing its alt attribute entirely (not merely empty) — several screen readers fall back to reading the src filename aloud as a last resort, which is rarely meaningful to the user.
Fix: Add a real, descriptive alt attribute — this failure mode is a strong signal that the alt attribute is missing outright, not just empty.

🎯 Key Takeaways

  • Semantic tags are read by more than a rendering engine — screen readers, browser extensions, search crawlers, and Reader Mode all depend on the tag being genuinely correct, not merely styled to look correct.
  • Landmark elements (header, nav, main, aside, footer) let screen reader users jump directly between page regions with a keyboard shortcut, exactly like a sighted user visually scanning a layout.
  • The First Rule of ARIA: use a native HTML element with the behavior you need before reaching for role and other ARIA attributes to recreate that behavior manually.
  • aria-label supplies an accessible name directly; aria-labelledby points to existing visible text for that name; aria-describedby adds supplementary description after the name, commonly used for form hints and errors.
  • Good alt text conveys meaning or purpose, phrased as a natural sentence, without "image of" prefixes. alt="" is the correct, deliberate choice for purely decorative images — it is not a mistake.
  • A placeholder is never a substitute for a real, connected <label> — it disappears once typing starts and is not reliably announced as a label at all by most screen readers.
  • Div soup fails real keyboard-only and screen-reader users directly, not just search rankings — unreachable "links" and "buttons," missing landmarks, and missing heading structure are all invisible in a normal sighted visual review.
  • Nearly every accessibility fix changes only the underlying markup, not the rendered visual design — accessibility and visual design are largely independent axes, not a tradeoff against each other.

What comes next

Module 11 opens Phase 2 of the HTML track with a survey of HTML5's browser-facing APIs — custom data-* attributes and the JavaScript dataset property that reads them, the contenteditable attribute, and the native drag-and-drop API.

Module 11 → HTML5 APIs Overview
Share

Discussion

0

Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.

Continue with GitHub
Loading...