12 - CSS JS Integration & Accessibility
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 1lang="en"on<html>charset="UTF-8"in<head>viewportmeta tag in<head>- Descriptive
<title>tag - One
<h1>per page, logical heading order - Every
<img>has analtattribute - 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-labelandaria-pressedattributes
Project 2 — Accessible Contact Form
Build a fully accessible contact form:
- Every input has a visible
<label>linked byfor/id - Icon-only buttons have
aria-label - Use
requiredon 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 downloadedalt=""on decorative images | descriptive alt on meaningful images- Every
<input>needs a<label for="...">matching the input'sid - ARIA:
aria-label,aria-hidden,aria-expanded,role,aria-live - First Rule of ARIA: use native HTML elements first
- Never remove
:focusoutline — keyboard users rely on it
← 11 - Layout Basics | Back to → 00 - HTML Tutorial MOC