Blog

What we got wrong on this site, and what we had not done

The last episode: three bugs that survived every review because none of them appear where people look, and the work we kept deferring until writing this forced our hand.

Published

The five episodes before this one were about decisions that were thought through. This one is about the ones that were not.

Three bugs sat on the live site for days. They went past several pairs of eyes and nobody saw them — not because nobody was looking, but because none of the three appear in the places people look.

One: images drawing a wider corner than the box clipping them

The cards on the home page have a 20 pixel corner. The image inside each one was told to have no corner of its own, because it sits flush to the card edge and should borrow the card's.

That instruction never took effect. The image was drawing a 32 pixel corner, so the card's own corner showed as a white sliver around all four corners of every image.

The cause: two CSS utilities that both set border-radius on one element do not resolve in the order written in the markup. They resolve in the order the build tool happened to put them in the stylesheet, which is not something we control. Writing rounded-none last does not make it win.

The fix we chose was not to raise that instruction's priority. It was to make the mistake impossible to write. The frame's corner is a property passed in directly rather than a class passed in to override another class. With nothing to conflict, there is nothing to lose.

Then we wrote a script that walks every element on a page, compares its computed corner radius against the radius of the ancestor clipping it, and ran it across nine pages. No remaining cases.

The lesson. When a bug comes from two things being able to contradict each other, fix the contradiction, not the outcome.

Two: a dark page with a white band across it

Dark mode was correct in every section, and there was a white band straight across the client logo strip.

The cause: the page background was set on body alone. The gaps between sections, and the area you see when you scroll past the end of the page, take their colour from html first. Anywhere a section did not paint its own background, the browser's white came through.

This was completely invisible in light mode, because white over white is white. The bug had been there since the first day and only introduced itself when there was a dark theme to reveal it.

The lesson. A new feature does not only add new code. It exposes old assumptions that were never tested, because nothing had ever asked them a question.

While fixing it we also set color-scheme, which carries the theme into the scrollbars, the form controls and the overscroll gutter. Before that it was a dark page sitting inside a white frame.

Three: one brand colour doing two jobs

Brand blue was used both to fill buttons and to be read as link text.

On white it does both jobs well. Once there was a dark ground, the same blue was unreadable as text, so we lightened it — and every filled button on the site became pale blue with white text on top, which was worse than what we started with.

The problem was never the colour value. It was that one value was being asked two questions with different answers. We split it in two: the fill stays the brand's own blue in both themes, and type gets its own token, which is the only one that moves.

The lesson. A colour system named after what the colours are breaks the moment there is a second theme. One named after what they are for does not.

What we had not done, until writing this

When we planned this series, the last episode was always going to include a section called "what we know is still missing", because writing about accessibility while quietly skipping the parts we had not done is not honest.

Then we wrote the list out, and it turned out to be short enough to simply do.

A skip link. This site's navigation has two mega menus. Somebody using only a keyboard had to press Tab through a dozen links to reach the content, on every page they opened. The first Tab on any page now lands on a link straight to the main content.

Focus indicators that can actually be seen. Previously only some buttons had one; everything else fell back to the browser default, which is a thin dark outline — very nearly invisible against the navy footer and the hero. An invisible focus ring is not the same as no focus ring: it means a keyboard visitor has no idea where they are on the page. There is now one rule for the whole site, drawn in the local text colour, so it is legible on the white sections, on the navy, and over the gradient.

Increased contrast. iOS and macOS call it Increase Contrast; Windows has its own contrast themes. The people who turn it on are usually low vision, or reading a screen in direct sunlight. With it on, the muted greys move towards the body text colour, hairline rings become real borders, and all the decorative lighting switches off — because washing colour across text is precisely what that setting is asking us to stop doing.

Reduced transparency. The same setting that flattens the frosted surfaces in iOS and macOS. This site uses a blur behind exactly two panels, the navigation bar and the mobile drawer, and both are perfectly legible as solid ones.

What is genuinely still missing

We have not tested systematically with a real screen reader. Reading the HTML structure and believing it probably sounds right is not the same thing as sitting and listening to VoiceOver or NVDA read the page.

Nor have we tested with people who use these tools every day, which is the only test that tells you whether the order of the content makes sense.

It is written down here so that it is a visible debt rather than a silent gap.

Closing the series

The first five episodes might read like a site where everything was thought through. This episode is the part that makes that picture accurate.

What we can reasonably claim is not that we never got it wrong. It is that when we did, we asked why the mistake was writable in the first place, and fixed it there. A fixed bug is one bug gone. A fixed cause is the whole family of them that never happens.

About the author

Portrait of Film

Film — Wisit. A businessman who still does his own BA work more often than he probably should, and writes a fair bit of code, front and back. Runs two or three small businesses. Follows technology and business obsessively, in Thailand and everywhere else. Off the clock: physics, astronomy, DIY, and anything to do with networks. Music always on, though he cannot sing. Plays instruments anyway, badly. Plays a lot of sport, racket sports above all. One flaw: he barely touches video games.

Written with Claude Opus 5