Structural sibling to Most CSS Resets Solve the Wrong Problem same distinction, different layer.
Also available in Español
The Problem
A production site ships. The design system rebuilds typography, spacing, and states through utility classes. Visual QA passes on desktop. Visual QA passes on mobile. The layout looks intentional, considered, correct.
Then someone reaches for the Tab key.
Nothing highlights. No outline marks the link, the button, the form field currently under keyboard control. The interface still works — a keyboard user can still submit the form, still follow the link, still open the menu. They just can't see where they are while doing it.
Nobody flagged this in review. It isn't a bug in the conventional sense — nothing crashed, nothing rendered incorrectly. It's a browser default that quietly stopped existing, and nobody replaced it.
Why the Problem Exists
Browsers generally provide a rendered focus indicator for keyboard-focused interactive elements. It isn't decoration. It exists so someone moving through a page without a mouse can track their own position in it — keyboard navigation with no visible indicator is navigation with no map.
Some broad CSS resets remove this by clearing default browser styling in one motion, which is the entire premise of a reset. That much is legitimate: browsers disagree on margin, padding, list markers, form control appearance, and a reset gets everyone starting from the same blank canvas.
The trouble starts when the same broad selector that clears cosmetic inconsistency also clears functional behavior, and nothing about the syntax marks the difference.
The First Principle
The cascade doesn't know the difference between a cosmetic default and a functional one. It only knows specificity, source order, and origin. *:focus { outline: none; } is exactly as valid, exactly as easy to write, and exactly as invisible in a diff as * { margin: 0; }. The browser applies it without complaint, because the browser has no concept of "this one mattered more."
The CSS series named this same shape of problem as normalization versus opinion — fixing a real cross-browser disagreement versus encoding an undocumented preference. HTML's version of that split runs on a different axis: decoration versus affordance.
Decoration is a visual choice the browser made in the absence of one from the author — default list markers, default heading sizes, default form control skins. It carries no functional weight. Removing it costs nothing.
Affordance is a signal that communicates state or enables interaction — focus indication, the pointer cursor on a clickable element, the disabled appearance on an inert control. It carries functional weight whether or not it's visually elaborate.
Visual QA checks appearance. It doesn't check for the absence of a signal that was never meant to be seen except at the moment someone needs it — for focus indication, only when navigating by keyboard. A reviewer clicking through a staging site with a mouse never triggers the condition that reveals the problem. The QA process didn't fail. It was never pointed at the question that mattered.
Demonstrating the Principle
Compare two versions of the same button, styled identically for a mouse user:
/* 1. Decoration removed */
button {
margin: 0;
padding: 0.5rem 1rem;
border: none;
background: none;
}
/* 2. Decoration removed; focus affordance removed */
button:focus {
outline: none;
}
The one-line difference between the two is invisible to a mouse and invisible to a visual diff. It only shows up the moment someone tabs to the button and looks for where they are. The first version still tells them. The second has gone silent.
Catching this doesn't require exotic tooling. It requires asking, line by line, what each removed default was actually doing before deciding it's safe to remove.
The Pain Point
This isn't a hypothetical. A production site ran through exactly this sequence: a broad reset, a utility-driven rebuild of typography, spacing, and states, a full visual QA pass on desktop and mobile — and a shipped *:focus { outline: none; } with no replacement anywhere in the system.
Mouse users saw a polished interface. Keyboard users saw nothing at the exact moment they needed to see something. The reset didn't just remove a visual style. It removed a piece of interface state, as a side effect of clearing something unrelated — not a decision anyone made on purpose.
Saturday's Notes from the Pass rebuilds one small interface three ways: browser defaults with no reset, a nuclear reset matched to look identical, and a controlled reset that restores focus behavior on purpose. The first two look the same to a mouse. Only a keyboard tells them apart.
The Broader Lesson
This isn't really about CSS resets. It's about the difference between removing something and understanding what it was providing. Every platform ships default behavior nobody asked for and everybody benefits from until it's gone.
The failure isn't in removing defaults — systems get simpler and more intentional when someone takes explicit ownership of what used to be implicit. The failure is removing a default without knowing what it was doing, because the removal was easy and the cost stayed invisible until someone hit it.
Worth asking, the next time a reset goes into a new project: which lines are fixing a real cross-browser gap, and which ones are quietly deciding what the interface is allowed to communicate.
Top comments (0)