The Notebook · Vol. I, Issue № 03
May 2026 · Gilbert, Arizona

Notes from a software consultancy.

WEB · ACCESSIBILITY · · ~5 min read

Lighthouse-Driven Accessibility on headius.com

Practical accessibility fixes derived from Lighthouse audits, from descriptive link text to auto-detecting high contrast modes.

I ran Lighthouse on headius.com the other day – mostly just to check the SEO score, if I’m being honest – and came away with a to-do list that was less about search engines and much more about accessibility. Which, really, is exactly how it should be. Good accessibility is good SEO; they’re essentially the same thing, just viewed from different angles.

So, then, here’s what I found and fixed.

The footer had a “More” link under the Resources column that pointed to the resources page. Lighthouse flagged it because “More” is meaningless out of context and screen readers do pull links out of context. They’ll announce “More, link” and the user has no idea what “more” refers to. I changed it to “Talks & articles”, which describes what’s actually on the page and doesn’t repeat the column header it sits under.

Heading hierarchy

The footer column headers were <h4> elements, which meant the heading hierarchy jumped levels depending on what the page content ended with. Lighthouse doesn’t like that, and neither do screen readers that let users navigate by heading level.

But these aren’t really headings in the document outline sense. Rather they’re labels for navigation groups. So I replaced them with <strong> elements and moved the semantic meaning to aria-label on the parent <nav>:

<nav aria-label="Resources">
  <strong>Resources</strong>
  <ul>...</ul>
</nav>

The visual styling stays the same (with display: block and font-weight: normal on the <strong> to match the old <h4> appearance), but the document outline is clean regardless of what heading the page content ends on.

The Social column in the footer had “Headius” twice – once for LinkedIn, once for Facebook – and “@JRuby” twice for X and Mastodon. Sighted users can tell them apart by the SVG icons, but a screen reader would just announce “Headius, link” twice with no way to distinguish them.

The fix was adding aria-label to each social link: “Headius on LinkedIn”, “Headius on Facebook”, “@JRuby on X”, “@JRuby on Mastodon”, and so on. The visible text doesn’t change, but screen readers now announce the platform name alongside the account name.

Auto-detecting high contrast

This is the one I’m most pleased with. The site already auto-detects prefers-color-scheme to choose between light and dark themes. As it turns out there’s an equivalent media query for contrast preferences: prefers-contrast: more. Browser support is remarkably solid these days, and it slots right into the existing auto-detection logic without much fuss.

So, now, if your operating system is set to high contrast mode, you’ll automatically get the high-contrast theme. It feels like the right thing to do. Let the OS communicate the user’s needs directly to the site, rather than making them hunt for a toggle. And just like with light/dark detection, there’s a change event listener so toggling the OS setting updates the site in real time.

Lighthouse flagged something I hadn’t considered: “Links rely on color to be distinguishable.” At first I messes with the color to increase the contrast, but it kept failing. Turns out this isn’t always about the contrast ratio, it’s about the fact that some users can’t perceive colour differences at all. If the only visual distinction between a link and surrounding text is that the link is a different colour, a colour-blind user can’t tell it’s interactive. This already had a high contrast ratio, but it was dark text with an equally dark, though different, link color and that’s what caused this particular failure.

The fix was really simple. Just underline links by default in high-contrast mode. The site normally uses text-decoration: none on links (with underline on hover), which is fine when the colour difference is obvious. But in high-contrast mode, links should be underlined by default. It’s one CSS rule:

a {
  [data-theme="high-contrast"] & {
    text-decoration: underline;
  }
}

I think this is the right call for any high-contrast theme, not just because Lighthouse says so. If someone has opted into (or been auto-detected into) high-contrast mode, they’re telling you that visual subtlety isn’t working for them. An underline is the most universally understood affordance for “this is a link”. It’s part of the way the web works by default. Removing it in a theme designed for accessibility would be working against the user. After making the change, Lighthouse passed these links, so it seems it’s aware of the underline decoration in this context.

Theme via query string

While I was in the theme code, I added support for a ?theme=high-contrast query string parameter. The primary reason was practical: I wasn’t running Lighthouse in Chrome, I was using a remote auditing service where I don’t control the browser at all. I couldn’t click the theme switcher even if I wanted to. But I could change the URL being tested, which meant giving the site a way to accept the theme choice from the URL itself was the path of least resistance.

The parameter saves the value to localStorage so the preference persists beyond the initial page load, which has a nice secondary benefit: I can share a link with the client to show them a specific theme without having to explain where the theme switcher lives. It validates against the known theme list (auto, dark, light, high-contrast) and ignores anything else.

The Lighthouse loop

None of these changes were dramatic on their own. A link renamed here, an aria-label there, a media query check added. But collectively they moved the accessibility score from “mostly fine” to “actually good”, and more importantly, they made the site work better for people who rely on assistive technology.

Lighthouse is a blunt instrument. It catches the mechanical issues, not the experiential ones. But it’s a useful starting point, and the fixes it suggests are almost always worth doing. The high-contrast auto-detection, in particular, was something I wouldn’t have thought about without the nudge from the contrast ratio warnings. Sometimes the tool that tells you your links aren’t contrasty enough leads you to discover that your OS already knows what your users need, you just have to listen.