refactoring-ui
Back to list

s0xDk/refactoring-ui

Refactoring UI

GitHub

Design and improve user interfaces using Refactoring UI rules for constrained spacing, type, color, shadow scales, hierarchy, and depth.

162 installsVisualSystemsCraft3 demos

Real-world examples

Live HTML demos for this skill — rendered directly in the page. 3 examples.

  1. 01

    Ashworth job ticket

    Cloth-case ticket for Weather on the Broads. Weight and color carry the hierarchy, the specs identify themselves, and Cancel stays a text link until the dialog, where it is the only primary action.

  2. 02

    North Ferry hold

    Two seats on the 16:40 to Rockland. The ticket overlaps the band, shadows split into a soft cast and a tight contact, and the type on the blue is a lighter blue — grey and faded white are the broken version.

  3. 03

    Kiln & Clay signup

    Tuesday wheel at the Hebden Bridge studio. Space around each group is wider than space inside it, the class length is a set of cards, and the hint sits beside the name.

Skill markdown
# Refactoring UI

Visual design is not talent. It is a small set of systems decisions made **once**, plus a
handful of techniques for creating hierarchy. This skill is those systems and those
techniques.

The single biggest cause of amateur-looking UI is picking values ad hoc — 17px here,
`#3B82F6` there, `lighten(5%)` for a hover state. Design *from a scale*, always.

---

## The systems — use these, do not re-derive them

Pick from these lists. Never invent a value that isn't on one.

### Spacing and sizing

Base 16px, built from factors and multiples of it:

```
4  8  12  16  24  32  48  64  96  128  192  256  384  512  640  768
```

Tight at the small end, spreading out at the large end. **No two adjacent values may be
closer than ~25%** — that is what makes the choice obvious. A linear "multiples of 4"
scale fails: it does not help you decide between 120px and 124px.

Use it for margin, padding, width, height, icon sizes, border width — everything spatial.
Fix a small set of opacity values too (e.g. `.05  .1  .2  .4  .6  .8`) for disabled states,
overlays and hover tints, rather than eyeballing a slider each time. Same logic as the other
scales: decide once, reuse everywhere.

### Type scale

```
12  14  16  18  20  24  30  36  48  60  72
```

Not a modular scale built from a ratio (4:5, 2:3, golden ratio). Those produce fractional
pixel values that round inconsistently across browsers and are too sparse for interface
density — hand-picked values, chosen for how they feel, win instead.

**Units: `px` or `rem` only. Never `em`.** `em` is relative to the current font size, so a
`.875em` inside a `1.25em` parent computes to 17.5px — a value not in your scale. The
scale silently stops existing.

### Font weight

Two weights is enough:

- **400 or 500** — body and most UI text
- **600 or 700** — anything emphasized

Nothing below 400 in UI. To de-emphasize, use a lighter *color* or smaller *size* — never a
lighter weight.

### Color

You need far more colors than a five-swatch palette generator gives you.

- **Greys: 8–10 shades.** Almost all of a UI is grey — text, backgrounds, panels, borders,
  form controls. Three or four shades always runs out. Start at a very dark grey, not true
  black (true black looks unnatural).
- **Primary: 5–10 shades**, one or maybe two primaries.
- **Accents: 5–10 shades each** — destructive red, warning yellow, positive green, plus
  whatever else the product needs to distinguish (chart series, calendar events, tags). Ten
  colors × 5–10 shades is normal for a complex UI.

Name them `100` (lightest) → `900` (darkest), base `500`.

**Build the scale in this order:** pick `500` first (for a primary/accent, it should be a
shade that works as a button background). Then find the edges — `900` is usually your text
color, `100` a background tint; an alert component uses both, so design one and read the
two values off it. Then fill `700` and `300` as the perfect compromise between their
neighbours, then `800 600 400 200` the same way.

**Write colors as HSL, not hex.** `hsl(220, 95%, 34%)` and `hsl(220, 65%, 61%)` are
visibly related; `#03369E` and `#507DD7` are not.

**Never generate shades at runtime** with `lighten()` / `darken()`. That is how you end up
with 35 slightly different blues.

### Shadows — five elevations

```css
0 1px 3px  hsla(0,0%,0%,.2)   /* barely raised — buttons */
0 4px 6px  hsla(0,0%,0%,.2)   /* dropdowns */
0 5px 15px hsla(0,0%,0%,.2)
0 10px 24px hsla(0,0%,0%,.2)
0 15px 35px hsla(0,0%,0%,.2)  /* modals */
```

Choose by asking *where on the z-axis does this sit?*, not *what shadow looks nice?*.
Closer to the user = more attention. Shrinking a button's shadow on `:active` makes it feel
pressed; growing a list item's shadow when it's picked up for drag-to-reorder does the
reverse — it reads as "now above its siblings" and doubles as the drag affordance itself.

These five are the default and are fine everywhere. `references/techniques.md` gives a
refined **two-part** version of the same scale — parallel, but not identical values (its top
step is heavier). Use it when shadows are prominent in the design; use these when they
aren't. Don't mix the two in one project.

### Line-height and line length

Line-height is **inversely** proportional to font size, and proportional to line width:

- small text / wide columns → `1.5` to `2`
- large headlines → `1` is fine

Line length: **45–75 characters**, i.e. `max-width: 20em–35em`. This applies to the
paragraph even when the container around it is wider — mixed widths in one content area
look more polished, not less.

(`em` is correct *here* — measure should scale with the text it wraps. The "never `em`" rule
is scoped to the *type scale*, where `em` compounds through nesting. Don't "fix" this.)

### Border radius

Pick one and stay consistent. Small radius = neutral. Large radius = playful. None =
serious/formal. Mixing square and rounded corners in one interface always looks worse.

---

## The procedure

**1. Start w

…