Chapter 12 — CSS & JS Integration & Accessibility

Learning Outcome

Connect HTML with CSS and JavaScript, and build accessible web pages using ARIA and best practices.

11 - Layout Basics | Back to → 00 - HTML Tutorial MOC

12.1 Three Ways to Add CSS

Method 1: Inline CSS

<p style="color: blue; font-size: 18px; font-weight: bold;">Hello</p>
  • Highest specificity — overrides everything
  • Hard to maintain, not reusable
  • Use only for truly one-off, quick tweaks

Method 2: Internal CSS (<style> tag)

<head>
  <style>
    p { color: blue; }
    h1 { font-size: 2rem; }
    .highlight { background: yellow; }
  </style>
</head>
  • Good for single-page projects or email templates
  • Keeps styles and HTML in one file

Method 3: External CSS (Best Practice ✅)

<head>
  <link rel="stylesheet" href="styles.css">
</head>
/* styles.css */
p { color: blue; }
h1 { font-size: 2rem; }
  • Separate file — clean separation of concerns
  • One CSS file styles many pages — efficient
  • Browser caches the CSS file — faster page loads

Which Method to Use?

  • Small experiments / learning → internal <style>
  • Any real project → external CSS file always
  • Never use inline style for layout — only micro-overrides

12.2 Three Ways to Add JavaScript

Method 1: Inline JS (Avoid ❌)

<button onclick="alert('Hello!')">Click</button>

Method 2: Internal JS (<script> tag)

<body>
  <h1>Hello</h1>

  <!-- JS at the bottom of body — HTML loads first -->
  <script>
    document.querySelector('h1').style.color = 'red';
  </script>
</body>

Method 3: External JS (Best Practice ✅)

<head>
  <!-- defer: loads JS after HTML is parsed (recommended) -->
  <script src="app.js" defer></script>
</head>

defer vs async

defer async When downloaded Parallel with HTML Parallel with HTML When executed After HTML parsed As soon as downloaded Order preserved ✅ Yes ❌ No Use for Most scripts Independent scripts (analytics) Always Use defer

<script src="app.js" defer> is the modern best practice. It downloads in the background and runs after HTML is ready — no blocking, no timing issues.

12.3 Accessibility Fundamentals

Accessibility (a11y) means making your website usable by everyone — including people with visual, motor, or cognitive disabilities.

Why Accessibility Matters

  • 1 in 6 people worldwide have a disability (WHO)
  • Accessible sites rank better in Google
  • Many countries have legal requirements for accessibility
  • Good accessibility improves UX for everyone (captions help in noisy environments too)

12.4 Core Accessibility Practices

1. Alt Text on Images

<!-- ✅ Descriptive alt text -->
<img src="chart.png" alt="Bar chart showing 40% sales growth in Q4 2024">

<!-- ✅ Decorative image — empty alt (screen reader skips it) -->
<img src="divider-line.svg" alt="">

<!-- ❌ Useless alt text -->
<img src="chart.png" alt="image">
<img src="chart.png" alt="chart.png">

2. Label Every Input

<!-- ✅ Accessible -->
<label for="email">Email Address</label>
<input type="email" id="email" name="email">

<!-- ❌ Not accessible — no label -->
<input type="email" name="email" placeholder="Email">

3. Logical Heading Hierarchy

<!-- ✅ Correct hierarchy -->
<h1>Main Title (once per page)</h1>
  <h2>Section</h2>
    <h3>Sub-section</h3>
    <h3>Another Sub-section</h3>
  <h2>Another Section</h2>

<!-- ❌ Skipping levels -->
<h1>Main Title</h1>
<h4>Why did we skip h2 and h3?</h4>

4. Keyboard Navigation

All interactive elements must be usable with Tab key only — no mouse required.

<!-- tabindex="0" makes non-interactive elements focusable -->
<div tabindex="0" role="button">Custom Button</div>

<!-- tabindex="-1" removes from tab order (JS controlled) -->
<div tabindex="-1">Only focusable via JS</div>

<!-- Skip navigation link (first thing on page) -->
<a href="#main-content" class="skip-link">Skip to main content</a>
...
<main id="main-content">...</main>

12.5 ARIA Attributes

ARIA = Accessible Rich Internet Applications. Adds accessibility semantics to HTML.

<!-- aria-label: text label for screen readers (no visible text) -->
<button aria-label="Close dialog">
  <svg><!-- X icon --></svg>
</button>

<!-- aria-hidden: hide decorative elements from screen readers -->
<span aria-hidden="true">★★★★☆</span>
<span class="sr-only">4 out of 5 stars</span>

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

<!-- aria-live: announce dynamic content changes -->
<div aria-live="polite" id="status">
  <!-- Changes here are announced by screen readers -->
</div>

<!-- role: define element purpose -->
<div role="alert">Form submitted successfully!</div>
<div role="navigation">...</div>
<div role="search">...</div>

Common ARIA Attributes


First Rule of ARIA

"No ARIA is better than bad ARIA." If you can use a native HTML element instead, do that. <button> is better than <div role="button">. <nav> is better than <div role="navigation">.

12.6 Screen Reader Only Text

Sometimes you need text for screen readers but not visible on screen.

<style>
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
  }
</style>

<!-- Visible icon, hidden text for screen reader -->
<button>
  <svg aria-hidden="true"><!-- cart icon --></svg>
  <span class="sr-only">Add to cart</span>
</button>

12.7 Colour Contrast & Focus Indicators

<!-- Always ensure visible focus ring -->
<style>
  /* Never do this — removes accessibility -->
  /* :focus { outline: none; } */

  /* Do this instead — custom but visible focus -->
  :focus {
    outline: 3px solid #005fcc;
    outline-offset: 2px;
  }
</style>

WCAG Contrast Ratios

  • Normal text: minimum 4.5:1 contrast ratio
  • Large text (18px+ or 14px bold): minimum 3:1
  • Check with tools: WebAIM Contrast Checker, browser DevTools

12.8 HTML Best Practices Checklist

Before You Ship a Page

  • <!DOCTYPE html> on line 1
  • lang="en" on <html>
  • charset="UTF-8" in <head>
  • viewport meta tag in <head>
  • Descriptive <title> tag
  • One <h1> per page, logical heading order
  • Every <img> has an alt attribute
  • Every <input> has a <label>
  • External CSS in <link>, external JS in <script defer>
  • Semantic tags used (<header>, <main>, <nav>, etc.)
  • Tab through the page — is it navigable by keyboard?
  • No passwords or secrets in HTML comments

🚀 Recommended Projects

Project 1 — Styled Portfolio with JavaScript

Link an external style.css and app.js to your portfolio page.

  • CSS: set font, colours, and a two-column layout
  • JS: add a dark mode toggle button using document.body.classList.toggle()
  • Ensure the button has aria-label and aria-pressed attributes

Project 2 — Accessible Contact Form

Build a fully accessible contact form:

  • Every input has a visible <label> linked by for/id
  • Icon-only buttons have aria-label
  • Use required on required fields
  • Add a success aria-live="polite" div that gets filled with "Form submitted!" via JS
  • Test the entire form using only the Tab key

📌 Quick Recall

  • Inline CSS → attribute style="" | Internal → <style> in head | External → <link> (best)
  • JS placement: <script src="app.js" defer> in <head> (preferred) or before </body>
  • defer = runs after HTML parses | async = runs as soon as downloaded
  • alt="" on decorative images | descriptive alt on meaningful images
  • Every <input> needs a <label for="..."> matching the input's id
  • ARIA: aria-label, aria-hidden, aria-expanded, role, aria-live
  • First Rule of ARIA: use native HTML elements first
  • Never remove :focus outline — keyboard users rely on it

11 - Layout Basics | Back to → 00 - HTML Tutorial MOC