โ™ฟ Building for Everyone

You've learned to build beautiful, responsive, animated web pages. But here's a critical question: can everyone actually use them? Over 1 billion people worldwide live with some form of disability โ€” visual, auditory, motor, or cognitive. Web accessibility (often abbreviated a11y โ€” "a" + 11 characters + "y") ensures your sites work for all users, regardless of how they interact with the web.

And there's a second dimension: once your site is accessible to humans, can search engines understand it? SEO (Search Engine Optimization) is the art of helping Google, Bing, and other crawlers discover, parse, and rank your content. Accessibility and SEO aren't separate disciplines โ€” they're deeply intertwined. The same semantic HTML that helps screen readers also helps search engines.

๐Ÿ’ก
The A11y + SEO Overlap Semantic headings (<h1>โ€“<h6>), descriptive alt text, logical document structure, meaningful link text โ€” these all serve both screen reader users and search engine crawlers. Accessible sites naturally rank better.
โš ๏ธ
Legal Reality Web accessibility isn't optional. Laws like the European Accessibility Act (EAA), the Americans with Disabilities Act (ADA), and Section 508 require accessible digital services. Lawsuits over inaccessible websites have increased dramatically โ€” accessibility is a legal obligation, not just a nice-to-have.

๐ŸŒ Why Accessibility Matters

Accessibility benefits far more people than you might think. Permanent disabilities are just one part of the picture โ€” consider the spectrum of ability:

Type Permanent Temporary Situational
Visual Blind, low vision Eye surgery recovery Bright sunlight on screen
Motor Paralysis, tremors Broken arm Holding a baby
Auditory Deaf, hard of hearing Ear infection Noisy environment
Cognitive Dyslexia, ADHD Concussion Distracted, multitasking

When you design for accessibility, you design for everyone. Curb cuts were made for wheelchair users, but they help parents with strollers, delivery workers with carts, and travelers with suitcases. The same principle applies to the web โ€” accessible features benefit all users.

WCAG: The Standard

The Web Content Accessibility Guidelines (WCAG) are the global standard for web accessibility. WCAG 2.2 is organized around four principles โ€” POUR:

๐Ÿ‘๏ธ
Perceivable

Information must be presentable in ways users can perceive. Text alternatives for images, captions for videos, sufficient color contrast.

๐Ÿ–ฑ๏ธ
Operable

Users must be able to operate the interface. Keyboard accessible, enough time, no seizure-triggering content, navigable.

๐Ÿ“–
Understandable

Content and operation must be understandable. Readable text, predictable behavior, input assistance.

๐Ÿ”ง
Robust

Content must be robust enough for diverse user agents, including assistive technologies. Valid markup, proper ARIA usage.

๐Ÿ—๏ธ Semantic HTML is Your Foundation

The single most impactful thing you can do for accessibility is use semantic HTML. Every semantic element carries built-in accessibility information that assistive technologies understand natively โ€” no ARIA needed.

HTML
<!-- โŒ BAD: div soup โ€” invisible to assistive tech -->
<div class="header">
    <div class="nav">...</div>
</div>
<div class="main">
    <div class="article">
        <div class="title">My Article</div>
    </div>
</div>

<!-- โœ… GOOD: semantic elements โ€” accessible by default -->
<header>
    <nav aria-label="Main navigation">...</nav>
</header>
<main>
    <article>
        <h1>My Article</h1>
    </article>
</main>

Landmark Roles

Semantic landmarks create a navigational skeleton that screen reader users can jump between โ€” like a table of contents for the page structure:

HTML Element Implicit ARIA Role Purpose
<header> banner Site-wide header (when top-level)
<nav> navigation Navigation links group
<main> main Primary content (one per page)
<aside> complementary Related but secondary content
<footer> contentinfo Site-wide footer (when top-level)
<section> region (if labeled) Generic section (needs aria-label)

Heading Hierarchy

Screen reader users navigate by headings more than anything else. A logical heading hierarchy is crucial:

HTML
<!-- โŒ Skipping levels โ€” confuses screen readers -->
<h1>Page Title</h1>
<h4>Subsection</h4>  <!-- Skipped h2 and h3! -->

<!-- โœ… Logical nesting -->
<h1>Page Title</h1>
    <h2>Section</h2>
        <h3>Subsection</h3>
    <h2>Another Section</h2>

Alt Text for Images

Every <img> needs an alt attribute. The content depends on the image's role:

HTML
<!-- Informative: describe what it shows -->
<img src="chart.png" alt="Bar chart showing 60% mobile, 30% desktop, 10% tablet traffic">

<!-- Decorative: empty alt (not missing โ€” empty!) -->
<img src="divider.svg" alt="">

<!-- Functional (inside a link): describe the action -->
<a href="/"><img src="logo.png" alt="Home โ€” Company Name"></a>

๐Ÿท๏ธ ARIA Roles & Attributes

ARIA (Accessible Rich Internet Applications) fills the gap when HTML semantics alone aren't enough. ARIA doesn't change behavior โ€” it only changes what assistive technologies announce. Think of it as metadata for screen readers.

โš ๏ธ
The First Rule of ARIA Don't use ARIA if a native HTML element can do the job. <button> is always better than <div role="button">. Native elements come with built-in keyboard handling, focus management, and screen reader support.

ARIA Categories

Category Examples Purpose
Roles role="alert", role="dialog", role="tablist" Define what an element is
States aria-expanded, aria-checked, aria-disabled Describe the current state (dynamic)
Properties aria-label, aria-describedby, aria-required Provide additional context

Essential ARIA Attributes

HTML
<!-- aria-label: names an element (when no visible text) -->
<button aria-label="Close dialog">โœ•</button>

<!-- aria-labelledby: points to another element's text -->
<dialog aria-labelledby="dialog-title">
    <h2 id="dialog-title">Confirm Delete</h2>
    ...
</dialog>

<!-- aria-describedby: extra description -->
<input type="password" aria-describedby="pw-hint">
<p id="pw-hint">Must be at least 8 characters</p>

<!-- aria-expanded: toggle state -->
<button aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" hidden>...</ul>

<!-- aria-live: announce dynamic content -->
<div aria-live="polite">3 results found</div>

<!-- aria-hidden: hide from assistive tech (decorative) -->
<span aria-hidden="true">๐ŸŽญ</span>
๐Ÿ“Œ
aria-live Regions aria-live="polite" waits for the user to be idle before announcing. aria-live="assertive" interrupts immediately (use for urgent messages like errors). Dynamic content updates (search results, notifications, chat) should use live regions so screen readers announce changes.

โŒจ๏ธ Keyboard Navigation

Many users navigate the web without a mouse โ€” they use the keyboard, switch devices, or voice control. Every interactive element must be keyboard accessible. This is one of the most common accessibility failures.

Focus Management

Interactive HTML elements (<a>, <button>, <input>, <select>, <textarea>) are focusable by default. Non-interactive elements (<div>, <span>) are not โ€” and that's intentional.

Key Action
Tab Move focus to next interactive element
Shift+Tab Move focus to previous element
Enter Activate link or button
Space Activate button, toggle checkbox
Escape Close dialog/modal/popup
Arrow keys Navigate within widgets (tabs, menus, radio groups)

tabindex

HTML
<!-- tabindex="0": add to tab order (in DOM order) -->
<div role="button" tabindex="0">Custom button</div>

<!-- tabindex="-1": focusable via JS, NOT in tab order -->
<div id="modal" tabindex="-1">Focus me programmatically</div>

<!-- โŒ NEVER use tabindex > 0 โ€” disrupts natural order -->
<input tabindex="3">  <!-- DON'T do this -->

Focus Indicators

Never remove focus outlines without providing an alternative. The :focus-visible pseudo-class is the modern solution โ€” it shows focus styles for keyboard users but not for mouse clicks:

CSS
/* โŒ NEVER do this */
*:focus { outline: none; }

/* โœ… Custom focus style for keyboard users only */
:focus-visible {
    outline: 3px solid #4f46e5;
    outline-offset: 2px;
    border-radius: 4px;
}

/* Remove default for mouse users */
:focus:not(:focus-visible) {
    outline: none;
}

Skip Navigation Link

Keyboard users shouldn't have to Tab through the entire navigation on every page. A skip link lets them jump directly to the main content:

HTML + CSS
<!-- First element in <body> -->
<a href="#main-content" class="skip-link">Skip to main content</a>

<nav>...</nav>
<main id="main-content">...</main>
CSS
.skip-link {
    position: absolute;
    top: -40px;
    left: 0;
    background: #4f46e5;
    color: #fff;
    padding: 8px 16px;
    z-index: 100;
    transition: top 0.2s;
}

.skip-link:focus {
    top: 0;
}

๐ŸŽจ Visual Accessibility

Color Contrast

WCAG requires minimum contrast ratios between text and background. Low contrast text is unreadable for many users โ€” especially in bright sunlight or on low-quality screens:

Level Normal Text Large Text (โ‰ฅ18pt / 14pt bold)
AA 4.5:1 3:1
AAA 7:1 4.5:1
๐Ÿ’ก
Contrast Checking Tools Use WebAIM Contrast Checker, browser DevTools (Chrome's color picker shows contrast ratios), or the axe DevTools extension. Always test with real content, not just placeholder text.

Don't Rely on Color Alone

About 8% of men and 0.5% of women are color blind. Never use color as the only way to convey information โ€” always pair it with text, icons, or patterns:

HTML
<!-- โŒ Color alone โ€” invisible to color-blind users -->
<span style="color: red;">Error</span>

<!-- โœ… Color + icon + text -->
<span style="color: red;">โŒ Error: Email is required</span>

Text Readability

  • Minimum body text: 16px (browser default). Never below 12px.
  • Line height: 1.5โ€“1.8 for body text. Tight leading hurts readability.
  • Line width: 50โ€“80 characters. Very long lines cause reading fatigue.
  • Text must be resizable up to 200% without loss of content (WCAG 1.4.4). Use rem/em, not px for font-size.

Reduced Motion

We covered prefers-reduced-motion in Module 10. As a reminder: always respect the user's motion preferences:

CSS
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

๐Ÿ“ Accessible Forms

Forms are where accessibility failures happen most often. Every input needs a label, every error needs to be announced, and the entire form must be keyboard-operable.

Labels: The #1 Rule

HTML
<!-- โŒ No label โ€” screen reader says "edit text, blank" -->
<input type="email" placeholder="Enter email">

<!-- โœ… Explicit label โ€” proper association -->
<label for="email">Email address</label>
<input type="email" id="email" placeholder="you@example.com">

<!-- โœ… Implicit label (wrapping) -->
<label>
    Email address
    <input type="email" placeholder="you@example.com">
</label>

Error Messages

HTML
<label for="pw">Password</label>
<input type="password" id="pw"
       aria-describedby="pw-error"
       aria-invalid="true">
<p id="pw-error" role="alert">
    โŒ Password must be at least 8 characters
</p>

Grouping with fieldset/legend

HTML
<fieldset>
    <legend>Shipping Address</legend>
    <label for="street">Street</label>
    <input id="street" type="text">

    <label for="city">City</label>
    <input id="city" type="text">
</fieldset>

๐Ÿงช Testing Accessibility

Automated tools catch about 30โ€“40% of accessibility issues. The rest require manual testing. A good accessibility workflow combines both:

Automated Testing

๐Ÿ”ง
Lighthouse (Chrome DevTools)

Built into Chrome. Audits accessibility, performance, SEO, and best practices. Good starting point.

๐Ÿช“
axe DevTools

Browser extension by Deque. Industry-standard engine with zero false positives. More detailed than Lighthouse.

๐ŸŒŠ
WAVE

Visual overlay that highlights issues directly on the page. Great for seeing problems in context.

Manual Testing Checklist

โœ…
Quick Manual Tests:
  • Keyboard only: Unplug your mouse. Can you reach and operate everything with Tab, Enter, Space, Escape?
  • Zoom to 200%: Is all content still readable? Nothing cut off or overlapping?
  • Screen reader: Try macOS VoiceOver (Cmd+F5) or NVDA (Windows, free). Navigate your page โ€” does it make sense?
  • Color contrast: Check all text/background combinations, especially light gray text.
  • Focus indicators: Tab through the page. Can you always see where focus is?

๐Ÿ” SEO Fundamentals

Search Engine Optimization ensures your content is discoverable. Search engines crawl your HTML, analyze its structure, and rank it based on relevance, quality, and technical correctness. Good SEO starts with good HTML.

HTML for SEO

  • One <h1> per page โ€” clearly describes the page topic.
  • Logical heading hierarchy โ€” helps crawlers understand content structure.
  • Descriptive link text โ€” "Read our pricing guide" not "Click here".
  • Alt text on images โ€” search engines can't "see" images without it.
  • Semantic elements โ€” <article>, <nav>, <main> help crawlers identify content regions.
  • lang attribute โ€” <html lang="en"> tells search engines the content language.

The <title> Tag

The most important SEO element. It appears in browser tabs, search results, and social shares:

HTML
<!-- โŒ Vague, unhelpful -->
<title>Home</title>

<!-- โœ… Descriptive, includes brand -->
<title>Web Accessibility & SEO Guide โ€” Web Foundations | Mehdi Tmimi</title>

Meta Description

HTML
<!-- 150-160 characters max. Appears in search results. -->
<meta name="description"
      content="Learn web accessibility and SEO. Master ARIA roles, keyboard navigation, color contrast, meta tags, Open Graph, and structured data. Free course.">

Robots & Crawling

HTML
<!-- Allow indexing (default behavior) -->
<meta name="robots" content="index, follow">

<!-- Block indexing (private/admin pages) -->
<meta name="robots" content="noindex, nofollow">

<!-- Canonical URL โ€” prevents duplicate content -->
<link rel="canonical" href="https://example.com/page">

๐Ÿท๏ธ Meta Tags & Open Graph

When someone shares your link on social media, Open Graph tags control what appears โ€” the title, description, image, and type. Without them, platforms guess (usually badly).

Open Graph Protocol

HTML
<!-- Essential Open Graph tags -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://example.com/page">
<meta property="og:title" content="Page Title โ€” Site Name">
<meta property="og:description" content="A compelling 1-2 sentence description.">
<meta property="og:image" content="https://example.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">

Twitter Cards

HTML
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Short description">
<meta name="twitter:image" content="https://example.com/og-image.jpg">

Favicons

HTML
<!-- Modern favicon setup -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">

๐Ÿ“Š Structured Data (JSON-LD)

Structured data helps search engines understand your content beyond plain HTML. By adding JSON-LD (JavaScript Object Notation for Linked Data) to your page, you can tell Google exactly what your content represents โ€” an article, a recipe, a product, an event, a course โ€” and earn rich snippets in search results.

HTML
<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "Web Accessibility & SEO Guide",
    "author": {
        "@type": "Person",
        "name": "Mehdi Tmimi"
    },
    "datePublished": "2026-03-10",
    "description": "Complete guide to web accessibility and SEO.",
    "image": "https://example.com/article-image.jpg"
}
</script>

Common Schema Types

Schema Type Use For Rich Result
Article Blog posts, news articles Enhanced listing with date/author
Product E-commerce items Price, availability, ratings
Course Online courses Course info in search
FAQ FAQ pages Expandable Q&A in search results
BreadcrumbList Site navigation path Breadcrumb trail in search
๐Ÿ’ก
Validate Your Structured Data Use Google's Rich Results Test and Schema Markup Validator to check your JSON-LD. Errors in structured data won't break your page, but they'll prevent rich snippets from appearing.

โœ๏ธ Exercises

Starter

Exercise 1: Audit a Page with Lighthouse

Open Chrome DevTools โ†’ Lighthouse โ†’ check "Accessibility". Run the audit on any public website. Note the score and the top 3 issues found. For each issue, identify the HTML fix.

Starter

Exercise 2: Keyboard Navigation Test

Unplug your mouse (or disable your trackpad). Navigate through any website using only Tab, Shift+Tab, Enter, Space, and Escape. Document: Can you reach all interactive elements? Can you always see where focus is? Can you operate all menus and buttons?

Builder

Exercise 3: Fix an Inaccessible Form

Start with this inaccessible form: inputs with no labels, placeholder-only, no error association, no fieldset grouping. Fix all the issues using proper <label>, aria-describedby, aria-invalid, <fieldset>/<legend>, and focus indicators.

Builder

Exercise 4: Add SEO & Open Graph Tags

Take any HTML page you've built and add: a descriptive <title>, meta description, canonical URL, complete Open Graph tags (og:title, og:description, og:image, og:url), Twitter Card tags, and JSON-LD structured data.

Challenge

Exercise 5: Build an Accessible Navigation

Build a responsive navigation bar with: a skip-to-content link, proper <nav> landmark with aria-label, keyboard-operable hamburger menu (aria-expanded), focus trapping when the mobile menu is open, and :focus-visible styling. Test with keyboard only and VoiceOver/NVDA.

๐Ÿ“‹ Module Summary

๐Ÿ—๏ธ
Semantic HTML

Use native elements (<header>, <nav>, <main>, <button>). They carry built-in accessibility โ€” no ARIA needed.

๐Ÿท๏ธ
ARIA

aria-label, aria-labelledby, aria-describedby, aria-expanded, aria-live. Only use when native HTML isn't enough.

โŒจ๏ธ
Keyboard

Everything must work without a mouse. Use :focus-visible, skip links, logical tab order. Never tabindex > 0.

๐ŸŽจ
Visual

4.5:1 contrast ratio (AA). Don't rely on color alone. Support text resizing to 200%. Respect prefers-reduced-motion.

๐Ÿ”
SEO

Descriptive <title>, meta description, logical headings, canonical URLs, Open Graph, Twitter Cards.

๐Ÿ“Š
Structured Data

JSON-LD for rich search results. Use Schema.org types: Article, Product, Course, FAQ, BreadcrumbList.

Next Module โ†’

Module 12: Capstone โ€” Build & Deploy

Put everything together. Build a complete multi-page responsive website from scratch using all the skills from Modules 0โ€“11, and deploy it live on GitHub Pages.

โ†’