eloybermejo

One of each

One colour, one font, one radius rule. It sounds like the least important decision in the project and it is most of what makes an interface feel like anything.

The first thing I do on a new project is not the architecture. It is picking a font and a colour. I will happily spend an afternoon on that before a single component exists, and I know exactly how that sounds.

It is not stupid, and the reason is boring: everything you build afterwards inherits it. Every screen, every button, every empty state, every error nobody will ever read. Pick badly and you are not fixing one thing later, you are fixing all of them, which in practice means you never fix any of them.

Three decisions

Nearly everything I like the look of comes down to three:

  • One colour. Not a palette. One. The background and the text are near greyscale, and a single accent carries every piece of meaning: the links, the focus ring, the thing you are meant to click. When there is one accent, anything wearing it means something. When there are five, none of them mean anything.
  • One font. One family, and let size and weight do the hierarchy. Two fonts is a decision you have to keep making, on every new piece of text, forever. One font is a decision you make once.
  • One radius rule. Not one value, a rule. Something like: boxes get 6px, small inline things get 3px. Two numbers, and now every corner in the app is already decided.

That is it. That is the whole system, and it fits on a napkin.

This site, for example

There is one accent here, #7cabb2, and it is doing all of the work: the > in front of every list item, the links, the words I want to lean on. Everything else is the background colour at different distances from the text colour. One font, JetBrains Mono, sized up and down. Corners are 6px on anything box shaped and3px on anything small.

There is no fourth decision. I have never once had to open a file and ask which grey a border is supposed to be, because there is only one, and it is called --border.

Why the small system wins

The argument for the big design system is that it covers every case. The problem is that it covers every case. Twelve colour ramps and forty tokens is not a decision, it is a thing you now have to remember, and the moment you cannot remember it you start guessing.

That is the actual failure mode, and it is not ugliness. It is drift. One screen gets the slightly wrong blue, another gets an 8pxcorner because it felt right that afternoon, and none of it is wrong enough to notice on its own. It just slowly stops looking like one product. Three rules never drift, because you cannot forget three rules.

There is a second thing, which is speed. Most of the time I spend on an interface is not typing, it is deciding. Constraints delete the deciding. If the colour is already chosen, the question stops being "what should this look like" and starts being "what should this do", which is the question I actually wanted to be working on.

Extending it without ruining it

You do eventually need more than three things. The trick is to derive rather than invent:

  • Need a second text colour? Take the one you have and move it toward the background. That is where --text-weakand --text-weaker come from here. They are not new decisions, they are the same decision, quieter.
  • Need a second accent? Only if you need a second meaning. Destructive actions are a real second meaning. "This section felt like it wanted green" is not.
  • Need a new spacing value? You almost certainly do not. Take one you already have.

The test I use is whether I can name every colour in the project from memory. If I can, it is still a system. If I cannot, it stopped being one a while ago and nobody told me.

None of this is design talent, which I do not especially have. It is just refusing to make the same decision twice. An afternoon at the start, three rules you never break, and the whole thing comes out looking deliberate :)

← Back