I just bumped a client site from Lighthouse 78 to 100 in half an hour. Most a11y wins are cheap. They are not the glamorous part of the job and nobody tweets about them, but they are the kind of work where 30 focused minutes can turn a site from quietly hostile into quietly welcoming, and the diff is usually small enough to fit in a single pull request.
I run roughly the same loop on every theme that lands on my desk, whether it is a WordPress theme, a hand-rolled PHP template, or a static site built out of Astro or 11ty. The tools change a little, the checks do not. Here is the list I work through, in the order I work through it, with the tool I reach for and the fix in two or three sentences each.
The 30-minute checklist
1. Color contrast. Open the page in Chrome, run the Lighthouse accessibility audit, and let it flag every text node that fails 4.5 to 1 for body copy or 3 to 1 for large text. If you want to inspect a specific element, the aXe DevTools extension is faster and more precise. The fix is almost always nudging text colors a couple of shades darker on light backgrounds or lighter on dark ones, and updating the same token in your CSS variables or Tailwind config so it propagates everywhere at once.
2. Missing alt attributes on images. Lighthouse catches most of these, but I also run a quick grep -r 'img src' theme/ as a sanity check because Lighthouse only sees the page you loaded. Every meaningful image gets a real alt description. Decorative images get alt="", which is different from no alt at all and tells screen readers to skip them.
3. Heading order. Open the page outline with the headingsMap extension or just look at the Lighthouse heading order check. The rule is simple. One h1 per page, h2 for major sections, h3 inside those, no skipping levels. If your design uses a big visual heading inside the body that is really an h4 in the outline, style it with a class, not by promoting the tag.
4. Form labels. Every input needs a <label for="input-id"> or an equivalent aria-label. Placeholders do not count. They disappear the moment the user starts typing and screen readers handle them inconsistently. If the design hides the visual label, keep the element in the markup and visually hide it with a sr-only utility class so assistive tech still sees it.
5. Keyboard navigation. Click into the address bar, then tab through the whole page without touching the mouse. Can you reach every interactive element? Does focus go in a sensible order? Can you submit the form, open the menu, close the modal, all from the keyboard? If something is unreachable, it is usually a div with a click handler that should have been a button, or a custom dropdown that swallows focus.
6. Skip-to-content link. Add a link as the very first child of the body that jumps to the main content area. It can be visually hidden by default and become visible on focus. Keyboard users land on it on tab one, hit enter, and skip the entire nav. Two lines of CSS and three lines of HTML, and it is a noticeable quality of life win for anyone who does not use a mouse.
7. Focus rings. If your designer asked you to remove the default focus outline because it looked ugly, give it back. Either let the browser default through, or replace it with a custom ring that matches your brand and is at least as visible. The :focus-visible pseudo-class lets you show the ring for keyboard users only, which is usually what the designer actually wanted.
8. Buttons versus links. A button does something on the same page. A link takes you somewhere. Screen readers announce them differently and keyboard users interact with them differently. If your menu toggle is an <a href="#">, it should be a <button>. If your "Read more" is a button with a window.location inside, it should be a link. This one is boring and almost always wrong on at least three elements per page.
9. aria-label on icon-only buttons. Any button that only contains an icon, a hamburger, a close X, a search magnifier, needs an aria-label describing what it does. Without it, screen reader users hear "button" with no context. With it, they hear "close dialog button" and know exactly what they are about to do.
10. Prefers-reduced-motion. Wrap your animations in a @media (prefers-reduced-motion: no-preference) query, or at minimum add a @media (prefers-reduced-motion: reduce) block that disables transforms and long transitions. Users who have the OS-level setting turned on usually have it on for a reason. Respect it and your fancy parallax stops triggering motion sickness.
11. Lang attribute on html. Open view-source on the page. Does <html> have a lang attribute? It needs one. <html lang="en"> is enough for an English site. Screen readers use it to pick the right pronunciation engine, and search engines use it as a hint. WordPress themes usually have this via language_attributes() in header.php. Static themes often do not, and it is a one-line fix.
12. Form error messages. When a field is invalid, the error message needs to be tied to the input with aria-describedby, and the input itself should get aria-invalid="true". That way a screen reader actually reads the error when the user lands on the broken field, instead of leaving them to guess why the form will not submit. While you are in there, make sure the error is not communicated by color alone, because a red border is invisible to a chunk of your users.
How to actually do this in 30 minutes
The trick is not stopping. I open Lighthouse, run it, fix the top three issues, run it again. I tab through the page with the keyboard while I wait for the report. I do not get distracted by an unrelated CSS bug I happen to notice. I keep a notes file open and dump anything that is not strictly a11y into it for later. The 30-minute clock is real and the discipline of staying on the checklist is what makes the bumps from 78 to 100 happen instead of from 78 to 84 with a tab full of half-finished refactors.
If the site is bigger than one page, I run the same loop on three representative templates. The homepage, an article, a form-heavy page. Most a11y issues are template issues. Fixing them once fixes them everywhere they appear.
The honest closer
A11y is a 30-minute job per page and a forever job for the codebase. New components ship and the checklist starts over. New designers join and the focus rings disappear again. New content goes up and someone forgets the alt text. It is a habit, not a project.
Most users with a11y needs notice immediately. The rest just benefit silently. Bigger tap targets are easier for everyone. Visible focus rings help anyone using a keyboard, including the power user on your team. Reduced motion is a relief for people with vestibular issues and a non-event for everyone else. There is no downside to any of these fixes and the upside compounds across every visitor you will ever have.
Pick a page today. Set a timer for 30 minutes. You will be surprised how far you get.