AMDE 355 · Advanced Web Design · Week 12
Accessibility, Performance & Quality Assurance
Make the experience work for more people, load efficiently, and behave reliably across devices.
This week
A finished design is more than how it looks
A web experience can look polished in one browser on one computer and still be difficult to use elsewhere. Text may be hard to read, controls may be impossible to reach with a keyboard, images may take too long to load, or an interaction may fail when a visitor uses a phone.
This week focuses on three connected responsibilities:
- Accessibility: Can people with different abilities, devices, and input methods understand and use the experience?
- Performance: Does the page load and respond without unnecessary delay or oversized media?
- Quality assurance (QA): Have you tested the experience systematically rather than assuming it works?
These are design concerns, not last-minute technical chores. An interface is not successful if its most important content is unreadable, its controls cannot be operated, or it fails on the screen where someone needs it.
Learning objectives
By the end of this lesson, you should be able to:
- Identify common accessibility problems involving contrast, text alternatives, headings, labels, keyboard use, and motion.
- Use semantic HTML elements for buttons, links, forms, and page structure.
- Describe how oversized images, video, fonts, and scripts can affect page performance.
- Apply a few practical performance improvements to images and JavaScript loading.
- Use browser developer tools to inspect errors and test responsive layouts.
- Write and complete a repeatable QA checklist.
- Explain beginner JavaScript using the pattern find → listen → respond and debug a simple interaction systematically.
Part 1 · Accessibility
Accessibility begins with clear structure
Accessible design helps people access and understand the information on a page, including people who use screen readers, keyboard navigation, magnification, voice control, or device settings such as reduced motion. It also helps people using a small screen, a trackpad, a slow connection, or a bright outdoor environment.
Use meaningful HTML
Choose HTML elements based on what they mean, not just how they look. A heading should introduce a section. A link should take someone somewhere. A button should perform an action.
<!-- Better: a link takes the visitor to another page -->
<a href="projects.html">View projects</a>
<!-- Better: a button performs an action on this page -->
<button type="button" id="details-button">
Show project details
</button>
A link and a button may look similar, but they have different jobs. Do not use a clickable div when a real button would do. Native elements already provide important keyboard and assistive-technology behavior.
Write useful image alternatives
<!-- Describe the important visual information -->
<img
src="images/installation-view.jpg"
alt="Three large prints arranged in a row on a gallery wall"
/>
<!-- If an image is purely decorative, use an empty alt value -->
<img src="images/decorative-texture.png" alt="" />
Alt text should communicate the useful content or purpose of the image. Avoid writing “image of” unless it adds something necessary. For artwork, describe the relevant visual information in context; do not try to write a complete art criticism in the alt attribute. If the image is decorative and conveys no information, an empty alt value prevents unnecessary announcements.
Check color contrast
Text needs enough contrast against its background to remain readable. Do not communicate a status using color alone. For example, if an error message is red, it should also include words or another clear indicator.
- Check small text and text placed over photographs.
- Do not rely on a pale color just because it matches the visual identity.
- Test links and buttons in normal, hover, focus, and disabled states.
- Use a contrast checker during design and again after the page is built.
Give controls clear names
“Click here” or an icon with no accessible name may not explain what a control does. Prefer labels such as “Play interview audio,” “Show project details,” or “Filter photography.” The label should match the result the visitor can expect.
Part 2 · Keyboard and focus
Test the page without a mouse
Some visitors navigate using the keyboard, switch devices, or other input tools. A quick keyboard test is one of the easiest ways to discover interaction problems.
- Press Tab to move through interactive controls.
- Press Shift + Tab to move backward.
- Use Enter to activate links and buttons; use Space for buttons when supported by the browser.
- Check that the current control has a visible focus indicator.
- Make sure focus does not disappear behind a fixed header or become trapped in a component.
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
outline: 3px solid #4d7c0f;
outline-offset: 3px;
}
:focus-visible lets you style the focus indicator when the browser determines it should be shown, commonly during keyboard navigation. Avoid removing the outline unless you replace it with an equally clear indicator.
Part 3 · Performance
Make media efficient without sacrificing the work
Photography, video, animation, and web fonts can make a page visually rich, but large assets can slow loading. Performance is not just a developer concern: it affects whether a visitor can reach and enjoy the content.
Use images at sensible dimensions
- Export images close to the size they will actually appear on the page.
- Use an appropriate compressed format, such as WebP or AVIF when supported by your workflow.
- Keep a high-quality original separately; the website does not always need the full-resolution master.
- Use lazy loading for images farther down the page, but do not automatically lazy-load the main image visible immediately on arrival.
- Give images explicit width and height attributes when possible so the browser can reserve space and reduce layout shifts.
<img
src="images/process-detail.webp"
alt="Close detail of layered photographic marks"
width="1200"
height="800"
loading="lazy"
decoding="async"
/>
width and height tell the browser the image’s intended dimensions, helping it reserve the right amount of space. loading="lazy" can delay loading until the image is close to the viewport. decoding="async" allows image decoding to happen asynchronously where supported. These attributes do not make an enormous file small, so export optimization still matters.
Be thoughtful with video and audio
Video files can be much larger than images. Use a poster image, offer controls, and avoid autoplay with sound. If the video is decorative, ask whether a still image would communicate the idea with less loading cost. If the video is central to the work, preserve the intended experience while making the file as efficient as practical.
Load JavaScript carefully
Scripts can affect when a page becomes usable. If you use a separate JavaScript file, the defer attribute tells the browser to download the script while parsing the HTML and run it after the document has been parsed.
<script src="js/interactions.js" defer></script>
This is useful when the script needs to find buttons or other elements in the HTML. It helps avoid the common beginner problem where JavaScript runs before the button exists. Do not add extra scripts or libraries unless the project actually needs them.
Part 4 · JavaScript quality checks
Debug interactions using three questions
JavaScript is easier to troubleshoot when you do not treat it as one mysterious block of code. Break it into three jobs:
LISTEN: Is the event listener waiting for the right action?
RESPOND: Does the code make the expected change?
Example: an accessible show/hide control
<button
id="qa-details-button"
aria-expanded="false"
aria-controls="qa-details"
>
Show details
</button>
<div id="qa-details" hidden>
<p>Additional information about the project.</p>
</div>
// FIND: locate the button and the panel.
const qaButton = document.querySelector("#qa-details-button");
const qaDetails = document.querySelector("#qa-details");
// LISTEN: wait for a click on the button.
qaButton.addEventListener("click", function () {
// RESPOND: check the current state.
const willOpen = qaDetails.hidden;
// If willOpen is true, hidden becomes false (the panel opens).
qaDetails.hidden = !willOpen;
// Keep the accessible state and visible label in sync.
qaButton.setAttribute("aria-expanded", willOpen);
qaButton.textContent = willOpen ? "Hide details" : "Show details";
});
Plain-English walkthrough: The first two lines find the button and panel. The event listener waits for a click. When clicked, the code checks whether the panel is hidden. The ! symbol means “not,” so !willOpen sets the hidden property to the opposite of the state we want. Finally, the code updates the accessible state and the button text so they describe what is happening.
The short expression condition ? valueA : valueB is called a conditional expression. Here it means: “If willOpen is true, use ‘Hide details’; otherwise use ‘Show details.’” If this feels too compressed for your class, use a regular if / else statement instead:
if (willOpen) {
qaButton.textContent = "Hide details";
} else {
qaButton.textContent = "Show details";
}
Both approaches work. For beginners, the longer version may be easier to read because it spells out the decision. The best code for this class is code you can explain and maintain.
Common errors and what they often mean
- Nothing happens: Check the selector, script placement, and whether the event listener is attached.
- “Cannot read properties of null”: The selector probably did not find an element. Compare the HTML ID and JavaScript selector letter by letter.
- The panel opens but will not close: Check whether you are updating the hidden state on every click, not only setting it to false.
- The label does not match the state: Update the label in the same click handler that updates the panel.
- There is a syntax error: Check parentheses, quotation marks, braces, and the closing
});.
Part 5 · Quality assurance
Test the actual experience, not just the code
Quality assurance is a repeatable process for checking that a page works as intended. Testing should include more than opening the page once and deciding that it looks good.
A practical test sequence
- Open the page in a desktop browser and check the main layout.
- Resize the browser to a narrow mobile width. Look for overflow, tiny text, and awkward image crops.
- Use Tab and Shift + Tab to test keyboard order and visible focus.
- Activate every button, link, menu, filter, and show/hide control.
- Reload the page and test again from its initial state.
- Check images, video, audio, captions, and alternative text.
- Open the developer console and look for errors.
- Check for horizontal scrolling that is not intentional.
- Ask another person to complete a simple task without coaching them.
- Record issues and make a second pass after changes.
Quick checklist
- Headings describe the page structure.
- Links and buttons have clear labels and appropriate purposes.
- Images have appropriate alt text.
- Text and controls have sufficient contrast.
- Keyboard focus is visible and in a logical order.
- Media controls are usable and do not unexpectedly play sound.
- Motion is purposeful and reduced-motion preferences are considered.
- Images are sized and exported appropriately.
- JavaScript interactions work repeatedly and communicate their state.
- The page has been checked at mobile and desktop widths.
- The console has been checked for errors.
In-class assignment
Accessibility, performance, and QA audit
Choose one of your existing project pages or the multimedia experiment from Week 11. Conduct a short audit, fix the most important issues you find, and document the changes.
Required deliverables
- A brief audit list containing at least five observations.
- At least three implemented improvements. Aim to address more than one category, such as accessibility, performance, and interaction reliability.
- A working keyboard test of all key controls.
- A mobile-width check with at least one screenshot before or after revision, as directed by the instructor.
- A short note describing one JavaScript interaction and how you verified it.
Suggested work order
- Test before changing anything so you have a clear starting point.
- Record the problems you can reproduce.
- Prioritize issues that block content or prevent someone from using a key control.
- Make small, targeted changes.
- Repeat the same tests to check that the changes worked and did not introduce new problems.
Reflection prompt: Which issue had the greatest effect on the visitor’s experience? What did you learn by testing with a keyboard or narrow viewport instead of relying on appearance alone?
Instructor-only material · Remove before publishing to students
Instructor Layout Code — Step by Step
Teaching emphasis: Frame accessibility, performance, and QA as parts of visual and interaction design. Students should leave with a repeatable process they can use on every project, not a list of rules they only consult at the end. For JavaScript, keep the focus on identifying the element, identifying the event, and explaining the response in plain language.
Suggested demonstration A: Keyboard test
- Open a student example or a prepared project page.
- Put the mouse aside and press Tab several times.
- Ask students to name which element currently has focus.
- Look for a clear outline or other visible focus indicator.
- Activate a button with the keyboard and verify that it performs the same essential action as a pointer click.
- Discuss any confusing focus order or control that cannot be reached.
Suggested demonstration B: Performance-aware image markup
Compare an oversized source image with an exported web-sized version. Explain that changing the CSS display size does not necessarily reduce the bytes downloaded. The goal is to deliver a suitable asset and then use CSS to lay it out.
<img
src="images/work-detail.webp"
alt="Detail of a layered print showing blurred movement"
width="1200"
height="800"
loading="lazy"
/>
Explain each attribute in one sentence. Then ask students when lazy loading is appropriate. Emphasize that an image already visible at the top of the page may need to load immediately, while images further down can often be loaded later.
Suggested demonstration C: Debug JavaScript in stages
Show the complete code first, then temporarily remove pieces to model how a developer isolates a problem. Do not begin by making students read a long error message without context.
const qaButton = document.querySelector("#qa-details-button");
console.log(qaButton);
Explain that console.log() prints a value in the browser console so you can inspect it. If the output is the button element, the selector found it. If the output is null, the selector did not find a matching element. The most likely beginner causes are a mismatched ID or a script that ran before the HTML existed.
qaButton.addEventListener("click", function () {
console.log("The button was clicked.");
});
If the message appears after clicking, the element was found and the event listener is working. If not, check the element, the event name, and whether an earlier JavaScript error stopped the script.
qaButton.addEventListener("click", function () {
qaDetails.hidden = !qaDetails.hidden;
});
This abbreviated version toggles the panel, but it does not update the button label or aria-expanded. Use it only to demonstrate the basic state change, then return to the complete accessible example so students see that an interaction should communicate its state consistently.
Explain the JavaScript vocabulary in everyday terms
const: create a name for a value or element reference.document: the current web page.querySelector(): find the first element that matches a CSS-style selector.addEventListener(): wait for an event, such as a click, and run instructions when it happens.function () { ... }: the group of instructions to run after the event.hidden: a built-in property that controls whether an element is hidden.setAttribute(): set an HTML attribute, such asaria-expanded.textContent: read or change the text inside an element.!: read this as “not”; it reverses a true/false value.if / else: choose between instructions based on a condition.console.log(): show a value in the browser console while testing.
Common teaching pitfalls
- Do not imply that adding an alt attribute automatically makes every image accessible; the text still needs to be appropriate.
- Do not ask students to fix every issue at once. Have them prioritize blockers, then retest.
- Do not remove keyboard focus styling to make a design look cleaner.
- Do not teach “make all images lazy” as a universal rule; the loading strategy depends on where the image appears and how important it is.
- Do not introduce multiple JavaScript patterns at the same time. Use the same find → listen → respond sequence from earlier lessons.
Suggested class pacing
- 10 minutes: Introduce accessibility as part of design quality.
- 15 minutes: Demonstrate semantic elements, alt text, contrast, and keyboard focus.
- 10 minutes: Discuss image sizes, loading behavior, and external script placement.
- 15 minutes: Debug the show/hide interaction in three stages: find, listen, respond.
- Studio work: Students audit and revise a page, then repeat their tests.
- Closing: Have each student share one problem found, one change made, and one retest result.