DEV Community

Sherotree
Sherotree

Posted on

Maintain a banned CSS patterns list the agent must respect

I used to paste “follow our design system” into every agent prompt. The PR still arrived with !important, magic z-index: 9999, and a one-off hex that matched nothing in the theme.

The agent wasn’t being rebellious. It just didn’t know which habits we had already decided were off-limits.

So I keep a short banned CSS patterns list next to the tokens file, and I paste it into UI prompts the same way I paste the ownership map.

What goes on the list

Not “write good CSS.” Specific patterns that keep showing up in agent diffs and keep failing review:

# banned-css.md (keep under ~30 lines)

Banned — do not introduce:
- `!important` (except existing legacy files listed below)
- hardcoded hex / rgb outside `tokens.css` / theme modules
- `z-index` above 20 without a comment pointing at the stacking doc
- `position: absolute` for layout that flex/grid already solves
- `font-size` / `line-height` / spacing as raw px when a token exists
- `outline: none` without a visible `:focus-visible` replacement
- `overflow: hidden` on interactive parents (clips focus rings / menus)
- vendor-prefixed properties we no longer need in supported browsers

Allowed escapes (name the file if you must use one):
- `src/legacy/datepicker.css` — still has `!important` until rewrite
Enter fullscreen mode Exit fullscreen mode

If a rule needs a paragraph of nuance, it doesn’t belong here. Put the nuance in the design-system doc and keep this file scannable.

Why a ban list beats “use tokens”

Token constraints tell the agent what to prefer. A ban list tells it what to refuse even when the model is “sure” a quick hack is fine.

Agents love:

  • patching specificity wars with !important
  • inventing a new gray because the closest token is “almost”
  • burying a modal under z-index: 99999 so it “just works”
  • killing the outline to make the mock look clean

Each of those is a one-line “fix” that becomes a week of cleanup. Naming them up front cuts the argument out of review.

How I wire it into prompts

I don’t dump the whole design system. I attach the ban list + the relevant token slice:

Edit only `src/checkout/ShippingForm.module.css` (+ colocated component).

Respect `docs/banned-css.md` literally. If a banned pattern seems required,
stop and propose an alternative instead of writing it.

Prefer tokens from `src/styles/tokens.css` for color, space, type.
Do not invent new color literals.
Max ~80 lines of CSS change.
Enter fullscreen mode Exit fullscreen mode

When the agent hits a wall (“I need higher z-index for the sticky bar”), I want a short note in the PR description — not a silent 9999.

What I reject in review

Reject on sight

  • New !important outside the legacy allowlist
  • Hex/rgb not imported from tokens
  • outline: none with no :focus-visible style in the same diff
  • z-index cliff without a stacking-context comment

Ask to split / redo

  • “Temporary” hacks with no ticket link
  • Copy-pasted utility classes that reintroduce banned patterns under a new name
  • Global selectors (div, button) to dodge a specificity problem the ban list was meant to prevent

If the ban list itself is wrong, we edit the list in a separate PR. We don’t “except this once” in the feature branch — that’s how the list dies.

Keeping the list alive

A dead ban list is worse than none. Once a month I:

  1. Grep the repo for each banned pattern and see what’s still real
  2. Drop rules nobody hits anymore
  3. Add the last two patterns that burned us in review
  4. Cap the file at roughly a screen of markdown

Agents follow short, concrete rules. They skim novels.

Prompt snippet I reuse

Follow docs/banned-css.md. No !important, no raw colors, no outline:none
without :focus-visible, no z-index > 20 without a stacking comment.
If blocked by a ban, propose an alternative and stop — do not “just make it work.”
Enter fullscreen mode Exit fullscreen mode

Tiny habit

Next time an agent sneaks !important into a “quick UI polish” PR, don’t only revert the line. Add that pattern to the ban list and paste the file into the next prompt.

You’re not teaching taste in chat. You’re giving the model a deny-list it can actually obey.

Top comments (0)