In CSS, what is the difference between a reset stylesheet and a normalize stylesheet, and where in a project's stylesheet order does it belong?
answer
- erase versus even out
- the browser already styled the page
- it has to come first
- modern versions are short and opinionated
- box-sizing, margin zero, font inherit
basics
~20 sA reset strips browser defaults — margins, list markers, heading sizes — down to a flat baseline. A normalize stylesheet keeps useful defaults and only patches cross-browser inconsistencies. Either one loads first, before base and component rules.
solid answer
~40 sBoth exist because browsers ship their own user-agent stylesheet, and it differs slightly between engines. A **reset** takes the scorched-earth approach: zero out margins, padding, borders and font sizing across a broad element list so you start from nothing and style everything yourself. A **normalize** stylesheet is surgical: it leaves sensible defaults alone (`<strong>` stays bold, lists keep their markers) and only fixes the places where browsers actually disagree, with a comment explaining each rule. Most teams today write a short opinionated reset instead of either extreme — `box-sizing: border-box` everywhere, `margin: 0` on text elements, `img { display: block; max-width: 100% }`, `input, button, textarea, select { font: inherit }`. Whichever you pick, it loads first. It uses low-specificity element selectors, so everything you write afterwards overrides it naturally.
code
css · 22 lines*, *::before, *::after {
box-sizing: border-box;
}
body, h1, h2, h3, h4, p, figure, blockquote, ul, ol {
margin: 0;
}
body {
min-height: 100vh;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img, picture, svg, video {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}go deeper
Be able to say plainly that browsers apply their own default styles, that a reset removes them and a normalize file only smooths out the inconsistent ones, and that either loads before your own CSS.
Explain why reset rules use low-specificity element selectors and why that placement makes later overrides work without hacks. Name the handful of declarations a modern reset actually contains and what each one fixes.
Argue the choice for a real codebase: what a blanket reset forces you to rebuild, why a separate base layer should sit after it, and how you upgrade or swap a reset without disturbing the project's typography.
Frame it as a boundary question — the reset is the contract between browser defaults and your design system. Be ready to say who owns that file, how changes to it are reviewed given they affect every page, and why a shared reset beats per-team variants.
## What browser defaults actually are Every browser ships a **user-agent stylesheet** — CSS the browser applies before yours. It is why an unstyled `<h1>` is large and bold, a `<ul>` is indented with bullets, and the page content does not start flush against the window edge. Typical declarations look like `body { margin: 8px }`, `h1 { font-size: 2em; margin-block: 0.67em }`, `ul { list-style: disc; padding-inline-start: 40px }`. These defaults are useful — an HTML document with no CSS at all is still readable — but they were never designed for your layout, and the exact numbers have historically differed between engines. Reset and normalize stylesheets are the two answers to that. ## The reset approach: erase A classic reset (Eric Meyer's `reset.css` is the canonical example) lists a large set of elements and flattens them: ```css html, body, div, span, h1, h2, h3, p, ul, ol, li, table, form { margin: 0; padding: 0; border: 0; font: inherit; vertical-align: baseline; } ``` You now start from a blank slate: nothing has spacing, nothing has a size, and everything renders at the inherited font. The tradeoff is that the erasure is indiscriminate. `font: inherit` also resets `font-weight` and `font-style`, so `<strong>` stops being bold and `<em>` stops being italic until you put them back. A reset therefore *requires* a base layer after it that restores the typography you actually want. ## The normalize approach: even out `normalize.css` (Nicolas Gallagher) takes the opposite stance. It preserves defaults that are worth keeping and targets only the specific elements and properties where browsers behave inconsistently or badly. Each rule carries a comment saying what it corrects. Nothing is flattened wholesale, so bold stays bold and lists stay lists, and you write less CSS to get back to a normal-looking document. The cost is the mirror image: you inherit a set of defaults you did not choose. If your design system says headings have no default margin, normalize will not do that for you. ## The modern middle ground Most teams now write a short reset of their own — a dozen or so rules, opinionated, entirely readable. Widely-copied versions (Andy Bell's and Josh Comeau's are two well-known published examples) tend to include: ```css *, *::before, *::after { box-sizing: border-box; } body, h1, h2, h3, p, figure, blockquote, ul, ol { margin: 0; } body { min-height: 100vh; line-height: 1.5; } img, picture, svg, video { display: block; max-width: 100%; } input, button, textarea, select { font: inherit; } ``` That last line matters more than it looks: form controls do not inherit the page font by default, so without it your buttons and inputs render in a browser-chosen font that does not match anything else on the page. ## Where it goes in the order The reset is the **first** thing in your stylesheet order, before base element styling, before components, before utilities. Two reasons: 1. **Cascade order.** Among declarations of equal specificity, the later one wins. Everything you author afterwards is meant to beat the reset, so the reset must come first. 2. **Specificity by construction.** A reset uses bare element selectors (specificity 0-0-1) or the universal selector (0-0-0). A component rule using a single class (0-1-0) already outranks it, so you never need an override hack to escape your own reset. If the project uses cascade layers, the reset goes in the earliest layer for the same reason. ## What a reset is not It is not your base layer. Page typography, the link colour, focus-visible styling, the type scale — those are design decisions and belong in a `base` file that loads immediately *after* the reset. Keeping the two files separate matters when you later upgrade or swap the reset: you want to replace the erasure without touching your typography. It is also not a performance measure. A reset is a handful of rules; adopting or dropping one does not meaningfully change how fast a page renders. Its whole value is predictability — starting every browser from the same known state so a layout bug is your bug, not a default you forgot about.
- Why do most teams write a twelve-line custom reset today instead of dropping in a full classic reset file?A full reset erases far more than a modern layout needs and then forces you to rebuild it. Flattening `<strong>`, `<em>` and every heading means writing base typography for elements you never intended to change. A short reset fixes the handful of defaults that genuinely fight modern layout — box sizing, stray margins, inline images, form-control fonts — and leaves the rest of the useful defaults working.
- A reset sets `margin: 0` on headings and paragraphs. What has to exist elsewhere so the page does not end up as a wall of text?A base layer directly after the reset. Once default margins are gone, vertical rhythm becomes something you own explicitly: a type scale for heading sizes, and deliberate spacing — either margins applied through a shared rule, or `gap` on the layout containers that hold the flow content. The reset removes accidental spacing precisely so the spacing that remains is intentional.
- If the reset and a component rule both set the same property on the same element, which wins and why?The component rule, essentially always. Resets select bare elements (`h1`, specificity 0-0-1) or use the universal selector (0-0-0), while component rules select a class (0-1-0), which outranks both. Even at equal specificity the component file loads later and wins on order. That is by design: a reset you have to fight with `!important` is a badly written reset.
saying these in an interview costs you the question
- Thinks reset and normalize are two names for the same file
- Says a reset makes the page render faster
- Loads the reset last so it 'wins' the cascade
- Calls `* { margin: 0; padding: 0 }` a complete reset
- Assumes form controls inherit the page font automatically