(Posts)

Blanksheet: A Principled CSS Reset

Mar 6, 2026 [ CSS , Reset]
show, don't tell https://github.com/P233/blanksheet

Blanksheet is a CSS reset built on five explicit principles; every rule traces back to one. Five principles classify every UA default on every element into exactly one category: reset it, keep it, skip it, set it, or normalize it. No property falls through the cracks, and no two principles compete for the same decision. The result is a reset you can audit against its own rules, and argue with on precise terms.

The five principles

Principle 1: Eliminate implicit layout

Zero every non-zero spatial property (margin, padding, vertical-align) so that all spacing in the final layout is fully under your control.

Media elements (<img>, <svg>, <video>, etc.) get vertical-align: bottom rather than display: block to close the baseline gap. Both work, but display: block breaks inline <svg> icons inside buttons and links.

Principle 2: Preserve text semantics

The test is scoped to a specific property on a specific element: does it carry semantic meaning that would be lost if reset? Remove font-weight: bold from <strong> and it looks identical to plain text. That’s semantic, so it stays. Same logic keeps font-style: italic on <em>, text-decoration on <a> and <del>, font-family: monospace on <code>, background-color on <mark>, and so on.

Heading font-size is the key exclusion. The semantic hierarchy lives in the HTML tag (<h1> through <h6>), not in the UA’s 2em0.67em scale. Every project defines its own type scale, so the UA value is universally replaced (→ P3). Heading font-weight: bold, by contrast, visually signals importance and stays.

Principle 3: Skip what developers always override

If no realistic production scenario keeps the UA default, resetting it is dead code; developers will override the reset anyway. Blanksheet simply skips it.

Property-level. Heading font-size, border on form controls / <fieldset> / <hr> / <iframe> / <dialog>, background on form controls and <dialog>, ::backdrop background. None of these UA values survive into production.

Element-level. <meter>, <progress>, and specialized inputs (date, time, datetime-local, month, week, color, range). In practice, projects always replace these entirely with custom design systems. Resetting properties on elements that won’t ship in their native form is dead code at a larger scale.

Worth noting: border is classified as a visual property (P3, not P1). border-width does occupy space, but developers override border for visual reasons, not spatial ones. Treating it as spatial would blur P1’s scope without meaningful benefit.

Principle 4: Apply real-world universal defaults

Conventions so broadly shared that omitting them creates universal boilerplate. The bar is high: must be correct for the vast majority of production projects, not merely convenient.

  • box-sizing: border-box via *, *::before, *::after
  • list-style: none on <ul>, <ol>, <menu>
  • border-collapse: collapse on <table>
  • font: inherit; color: inherit on form controls, fixing the UA inheritance break
  • appearance: textfield on <input type="number"> (spinners virtually always replaced)
  • list-style: none on <summary> (disclosure triangle virtually always replaced)

P4 actively sets a value to a convention that real-world projects have collectively settled on.

Principle 5: Normalize cross-browser inconsistencies

P5 is the catch-all for browser disagreements, applied only when browsers diverge on rendering the same element.

  • <sub> / <sup>: normalize positioning to prevent line-height disruption across engines
  • [type="search"]: WebKit’s non-standard appearance normalized to textfield
  • button::-moz-focus-inner: Firefox’s extra inner padding / border removed
  • text-size-adjust: 100%: prevents mobile Safari text inflation
  • ::placeholder opacity: Firefox’s reduced opacity normalized to 1
  • :-moz-ui-invalid: Firefox’s red box-shadow on invalid elements removed

P4 and P5 differ in scope: P4 applies when all browsers agree on a default that developers universally replace. P5 applies when browsers disagree on how to render the same element.

Where principles meet

One element, three principles

<h1>: margin is implicit layout, P1 resets it. font-weight: bold conveys importance, P2 preserves it. font-size: 2em is universally overridden, P3 skips it.

One declaration, two reasons

[type="search"] and [type="number"] share appearance: textfield for different reasons. [type="search"] is P5: WebKit’s non-standard appearance. [type="number"] is P4: all browsers agree on spinners, but they’re virtually always replaced. The principle system operates at the property-on-element level, not the declaration level.

What Blanksheet never does

No opinions: no cursor: pointer, no font-smoothing, no scroll-behavior: smooth. A reset subtracts UA defaults; it never adds behavior. And no !important — Blanksheet ships inside @layer reset, so any unlayered style wins automatically.

Every line has a reason

The source is annotated with [Principle N] references on every section, so every decision is traceable. If you think a rule doesn’t match its principle, or if you disagree with the principle itself, I’d genuinely love to hear about it. That’s the whole point of making the reasoning explicit.