# normalize.css User Guide

**normalize.css** is a small, dependency-free CSS file that makes browsers render
HTML elements more consistently. You drop it into your page **before** your own
styles, and it irons out the dozens of tiny differences in how Chrome, Firefox,
Safari, Edge, Internet Explorer, and Opera apply their default styling — without
wiping those defaults out the way a traditional "CSS reset" does.

This guide shows you how to install it, include it correctly, understand exactly
what it changes, customize it, and troubleshoot the rough edges. Everything here
is taken directly from the `normalize.css` source (v8.0.1) and the project's own
documentation.

> [!NOTE]
> normalize.css is a **single static stylesheet**. There is no command-line tool,
> no JavaScript, no configuration file, and no build step required to use it. If
> you can add a `<link>` tag or an `@import`, you can use it.

---

## 1. Quick Start

The fastest way to try normalize.css is to link it from a CDN and load it before
your own stylesheet.

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- 1. normalize.css FIRST -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css">

    <!-- 2. your own styles SECOND, so they win -->
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <h1>Hello, consistent world</h1>
  </body>
</html>
```

That is the entire integration: one stylesheet, loaded before yours. From here,
write your CSS as normal — you are now building on a level, cross-browser
foundation.

> [!IMPORTANT]
> **Order matters.** normalize.css must be loaded *before* your own CSS. It only
> sets sensible defaults; your stylesheet is meant to override them. Load it last
> and your own rules may be silently overridden by normalize.css.

> [!TIP]
> Pin a specific version (`@8.0.1`) rather than a floating "latest" URL. The
> project treats *any* change to a CSS rule as a breaking change (see
> [Versioning](#103-versioning-and-upgrades)), so an unpinned URL could shift your
> baseline styling without warning.

---

## 2. What normalize.css Does

normalize.css targets known, documented inconsistencies between browsers and
nudges each element toward one predictable rendering. Its design goals, as stated
by the project, are:

- **Preserves useful defaults**, unlike many CSS resets — headings still look like
  headings, lists still have bullets.
- **Normalizes styles** for a wide range of elements.
- **Corrects bugs and common browser inconsistencies.**
- **Improves usability** with subtle modifications (for example, the dotted
  underline on abbreviations).
- **Explains what code does** using detailed comments, so the file is also
  documentation.

### normalize.css vs. a CSS reset

A classic CSS *reset* (such as the well-known Meyer reset) strips **all** default
styling to zero — every margin, every font size, every list bullet — and forces
you to rebuild every element from scratch. normalize.css takes the opposite
approach: it **keeps** the helpful browser defaults and only fixes the parts that
differ between browsers or are outright bugs.

| Aspect | Traditional reset | normalize.css |
|--------|-------------------|---------------|
| Default margins/padding | Removed everywhere | Kept where useful (only `body` margin is removed) |
| Headings (`h1`–`h6`) | Flattened to body text | Preserved; only `h1`-in-`section` sizing is corrected |
| Lists | Bullets/numbers removed | Preserved |
| Approach | "Erase, then rebuild" | "Fix only what's broken" |
| File focus | Blanket overrides | Targeted, per-element, commented fixes |

> [!TIP]
> Because normalize.css preserves defaults, you generally write **less** of your
> own CSS than you would after a full reset — you only style what you actually
> want to change.

---

## 3. Installation

normalize.css ships as a single file. Choose whichever delivery method fits your
project.

=== "npm"

    ```bash
    npm install --save normalize.css
    ```

    Installs version `8.0.1` into `node_modules/normalize.css/normalize.css`.

=== "Yarn"

    ```bash
    yarn add normalize.css
    ```

=== "CDN"

    ```html
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css">
    ```

    Any npm-backed CDN (jsDelivr, unpkg, cdnjs) serves the package, because the
    npm `files` list publishes `normalize.css` and `LICENSE.md`.

=== "Download"

    Download the raw file and commit it into your project:

    ```bash
    curl -O https://necolas.github.io/normalize.css/latest/normalize.css
    ```

    Then link it locally:

    ```html
    <link rel="stylesheet" href="/css/normalize.css">
    ```

=== "Copy & paste"

    The file is only ~350 lines. For a one-page demo you can paste its contents
    straight into the top of your own stylesheet or a `<style>` block. Keep the
    license header comment intact (`/*! normalize.css v8.0.1 | MIT License ... */`).

After installing via a package manager, the published package contains exactly two
files:

| File | Purpose |
|------|---------|
| `normalize.css` | The stylesheet itself (the `main` and `style` entry point) |
| `LICENSE.md` | MIT license text |

> [!NOTE]
> The npm package intentionally ships **no** minified build. If you want a
> minified `normalize.min.css`, run the file through your own bundler or a CSS
> minifier — the project does not publish one (a request for this was declined,
> issue #911).

---

## 4. Including It in Your Project

How you wire normalize.css in depends on your toolchain. In every case the rule is
the same: **normalize.css comes first, your styles come after.**

### 4.1 Plain HTML

Two `<link>` tags, in order:

```html
<link rel="stylesheet" href="normalize.css">
<link rel="stylesheet" href="app.css">
```

### 4.2 Sass / SCSS

Forward it at the very top of your main stylesheet so it sits at the base of the
cascade:

```scss
// main.scss
@import 'normalize.css/normalize.css';

// ...your partials below
@import 'base';
@import 'layout';
@import 'components';
```

### 4.3 PostCSS / `postcss-import`

```css
/* app.css */
@import 'normalize.css';

/* your rules follow */
body { font-family: system-ui, sans-serif; }
```

### 4.4 webpack / Vite / bundlers

Import it once, as early as possible in your entry file (before your own CSS
imports), so it is emitted first in the bundle:

```js
// main.js (entry point)
import 'normalize.css';   // base layer — must be imported before app styles
import './styles/app.css';
```

### 4.5 React / Vue / Angular

The same import rule applies — put it in your root entry file so every component
inherits the normalized baseline:

=== "React"

    ```jsx
    // src/index.jsx
    import 'normalize.css';
    import './index.css';
    ```

=== "Vue"

    ```js
    // src/main.js
    import 'normalize.css';
    import './assets/app.css';
    ```

=== "Angular"

    ```json
    // angular.json -> projects > <app> > architect > build > options > styles
    "styles": [
      "node_modules/normalize.css/normalize.css",
      "src/styles.css"
    ]
    ```

> [!WARNING]
> In bundlers, CSS is applied in **import order**, not file name order. If your
> app styles "win" when they shouldn't, or normalize's defaults override your
> overrides, check that `import 'normalize.css'` appears **before** every one of
> your own style imports in the entry file.

---

## 5. What It Normalizes — Reference

normalize.css is organized into the same eight thematic sections you will find as
comment banners in the file. Each rule below lists the element(s) it targets, what
it does, and which browsers it is correcting. Use this as a lookup: if an element
renders unexpectedly, find it here to see whether normalize.css is already
touching it.

### 5.1 Document

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `html` | `line-height: 1.15` | Corrects the default line height in all browsers |
| `html` | `-webkit-text-size-adjust: 100%` | Prevents font-size adjustments after orientation changes in iOS |

### 5.2 Sections

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `body` | `margin: 0` | Removes the default body margin in all browsers (the one *opinionated* layout change) |
| `main` | `display: block` | Renders the `main` element consistently in Internet Explorer |
| `h1` | `font-size: 2em; margin: 0.67em 0` | Corrects font size and margin on `h1` inside `section`/`article` in Chrome, Firefox, and Safari |

> [!NOTE]
> `body { margin: 0 }` is the single layout opinion normalize.css holds. Everything
> else is a correction of a genuine bug or inconsistency. If you need the default
> 8px body margin back, simply re-add it in your own CSS.

### 5.3 Grouping Content

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `hr` | `box-sizing: content-box; height: 0` | Adds correct box sizing in Firefox |
| `hr` | `overflow: visible` | Shows the overflow in Edge and IE |
| `pre` | `font-family: monospace, monospace` | Corrects font-size inheritance and scaling of preformatted text in all browsers |
| `pre` | `font-size: 1em` | Corrects the odd `em` font sizing in all browsers |

> [!NOTE]
> The duplicated `monospace, monospace` is **intentional**, not a typo. The
> repetition is a deliberate hack that fixes how browsers inherit and scale the
> font size of preformatted text. Leave it as-is if you copy rules out of the file.

### 5.4 Text-level Semantics

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `a` | `background-color: transparent` | Removes the gray background on active links in IE 10 |
| `abbr[title]` | `border-bottom: none` | Removes the bottom border in Chrome 57- |
| `abbr[title]` | `text-decoration: underline dotted` | Adds correct text decoration in Chrome, Edge, IE, Opera, and Safari |
| `b`, `strong` | `font-weight: bolder` | Adds the correct bold font weight in Chrome, Edge, and Safari |
| `code`, `kbd`, `samp` | `font-family: monospace, monospace; font-size: 1em` | Same monospace inheritance/scaling fix as `pre` |
| `small` | `font-size: 80%` | Adds the correct small font size in all browsers |
| `sub`, `sup` | `font-size: 75%; line-height: 0; position: relative; vertical-align: baseline` | Prevents `sub`/`sup` from affecting line height in all browsers |
| `sub` | `bottom: -0.25em` | Positions subscript correctly |
| `sup` | `top: -0.5em` | Positions superscript correctly |

> [!TIP]
> The `abbr[title]` rule gives you a tidy dotted underline (with a solid underline
> as a fallback for older browsers). It is one of the "usability improvement"
> rules — give your abbreviations a `title` attribute to benefit from it:
> `<abbr title="HyperText Markup Language">HTML</abbr>`.

### 5.5 Embedded Content

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `img` | `border-style: none` | Removes the border on images inside links in IE 10 |

### 5.6 Forms

Form controls are where browsers differ the most, so this is the largest section.

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `button`, `input`, `optgroup`, `select`, `textarea` | `font-family: inherit; font-size: 100%; line-height: 1.15; margin: 0` | Makes form controls inherit your page font instead of the browser's; removes default margins in Firefox and Safari |
| `button`, `input` | `overflow: visible` | Shows overflow in Edge and IE |
| `button`, `select` | `text-transform: none` | Removes inherited text-transform in Edge, Firefox, and IE |
| `button`, `[type="button"]`, `[type="reset"]`, `[type="submit"]` | `-webkit-appearance: button` | Makes clickable button types stylable in iOS and Safari |
| `button::-moz-focus-inner`, `[type="button"]::-moz-focus-inner`, … | `border-style: none; padding: 0` | Removes the inner border and padding in Firefox |
| `button:-moz-focusring`, … | `outline: 1px dotted ButtonText` | Restores the focus outline Firefox loses from the rule above (keeps keyboard focus visible) |
| `fieldset` | `padding: 0.35em 0.75em 0.625em` | Corrects fieldset padding in Firefox |
| `legend` | `box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal` | Fixes text wrapping (Edge/IE), color inheritance (IE), and removes padding for consistency |
| `progress` | `vertical-align: baseline` | Adds correct vertical alignment in Chrome, Firefox, and Opera |
| `textarea` | `overflow: auto` | Removes the default vertical scrollbar in IE 10+ |
| `[type="checkbox"]`, `[type="radio"]` | `box-sizing: border-box; padding: 0` | Adds correct box sizing and removes padding in IE 10 |
| `[type="number"]::-webkit-inner-spin-button`, `…-outer-spin-button` | `height: auto` | Corrects the cursor style of the increment/decrement buttons in Chrome |
| `[type="search"]` | `-webkit-appearance: textfield; outline-offset: -2px` | Corrects the odd appearance in Chrome/Safari and the outline style in Safari |
| `[type="search"]::-webkit-search-decoration` | `-webkit-appearance: none` | Removes the inner padding in Chrome/Safari on macOS |
| `::-webkit-file-upload-button` | `-webkit-appearance: button; font: inherit` | Makes the file-upload button stylable in iOS/Safari and inherits font in Safari |

> [!IMPORTANT]
> The form font rule (`font-family: inherit; font-size: 100%`) is the change you
> are most likely to *notice*. Without normalize.css, `<button>`, `<input>`, and
> `<textarea>` use the browser's own UI font; with it, they inherit your page font.
> This is intentional and almost always what you want — but if a control suddenly
> looks different from the raw browser default, this rule is why.

### 5.7 Interactive

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `details` | `display: block` | Adds correct display in Edge, IE 10+, and Firefox |
| `summary` | `display: list-item` | Adds correct display (with disclosure triangle) in all browsers |

### 5.8 Misc

| Selector | What normalize.css sets | Why |
|----------|-------------------------|-----|
| `template` | `display: none` | Adds correct display in IE 10+ |
| `[hidden]` | `display: none` | Adds correct display in IE 10 (makes the `hidden` attribute work) |

---

## 6. Customizing and Extending

normalize.css gives you a baseline. You build on top of it with your own CSS.

### 6.1 Override after, never edit in place

The cleanest pattern is to leave `normalize.css` untouched and put your changes in
your own stylesheet that loads afterward. Because your rules come later in the
cascade (and CSS specificity ties break toward the last rule), they win:

```css
/* normalize.css set body margin to 0 — bring back a default margin if you want it */
body {
  margin: 8px;
}

/* normalize.css set links transparent — give yourself a brand color */
a {
  color: #0b5fff;
}
```

> [!TIP]
> Keeping normalize.css unmodified means you can drop in a newer version later by
> swapping one file, with no merge conflicts against your edits.

### 6.2 Be aware of the one opinion

The only purely *opinionated* layout rule is `body { margin: 0 }`. If your design
expects the browser's default 8px body margin, add it back yourself (as shown
above). Every other rule is a bug fix, so overriding those usually means you are
re-introducing a browser inconsistency — do it deliberately.

### 6.3 Removing rules you don't need

If you are targeting only modern evergreen browsers and never Internet Explorer,
some IE-specific corrections (for example the `main { display: block }` and
several `[type="…"]` box-sizing fixes) are no longer strictly necessary. You can
fork the file and delete the rules whose comments name only browsers you do not
support. Keep the file's structure and comments intact so the next person
understands what was removed.

> [!CAUTION]
> Do not delete a rule just because you do not recognize the browser it names. Many
> corrections (the form font inheritance, `sub`/`sup` line-height, the `abbr`
> underline) apply to **all** browsers, including the newest ones. Removing those
> brings back real inconsistencies.

---

## 7. Browser Support

normalize.css v8 officially supports:

| Browser | Supported versions |
|---------|--------------------|
| Chrome | Current |
| Edge | Current |
| Firefox | ESR and newer |
| Internet Explorer | 10 and newer |
| Safari | 8 and newer |
| Opera | Current |

> [!NOTE]
> Support for older engines (Android 4, Internet Explorer 9 and below, Safari 7
> and below) was **removed in v8.0.0**. If you still need those, you would have to
> use an older release of normalize.css — but doing so is rarely advisable on the
> modern web.

---

## 8. Troubleshooting

Each entry below follows the same shape: the symptom, why it happens, and what to
do. These are drawn from the project's documented "known issues" and from real
issues reported by its community.

### Issue: Form controls don't use my page font

**Cause:** This is normalize.css working as intended — `button`, `input`,
`select`, and `textarea` are set to `font-family: inherit; font-size: 100%`, so
they inherit from their container.

**Solution:** Nothing to fix if your container has the font you want. If a control
still looks wrong, set the font explicitly on it or on a shared ancestor:

```css
button, input, select, textarea {
  font-family: inherit;
}
```

**Prevention:** Define your base font on `body` (or `:root`) so every control
inherits it.

### Issue: `select` won't take my font weight or border styling

**Cause:** By default, Chrome and Safari on macOS allow only very limited styling
of `<select>` unless a `border` property is set, and the font weight on
`<optgroup>` cannot be safely changed in those browsers.

**Solution:** Set a `border` on the `select` to unlock further styling, and accept
that `optgroup` weight is not reliably controllable on macOS Chrome/Safari:

```css
select {
  border: 1px solid #999;
}
```

**Prevention:** For fully custom dropdowns, build a custom component rather than
restyling the native `select`.

### Issue: Checkbox/radio inputs ignore my `box-sizing`, padding, or width

**Cause:** Firefox's implementation of `[type="checkbox"]` and `[type="radio"]`
does not respect `box-sizing`, `padding`, or `width`. normalize.css already sets
`box-sizing: border-box; padding: 0` to make them consistent, but further sizing
is unreliable.

**Solution:** The project explicitly recommends **not** styling the box of native
checkboxes and radios. If you need custom visuals, hide the native control and
draw your own with a sibling element.

**Prevention:** Reach for a custom-control pattern instead of fighting the native
box model.

### Issue: The number input's decrement-button cursor flickers to a text cursor

**Cause:** Certain `font-size` values on `[type="number"]` cause Chrome to change
the cursor of the decrement button from `default` to `text`. normalize.css sets
`height: auto` on the spin buttons to mitigate the appearance.

**Solution:** Avoid unusual font sizes on number inputs, or set an explicit cursor:

```css
input[type="number"]::-webkit-inner-spin-button {
  cursor: default;
}
```

### Issue: I can't style a search input's font, padding, border, or background

**Cause:** Search inputs are not fully stylable by default. In Chrome and Safari
on macOS/iOS you cannot control `font`, `padding`, `border`, or `background`; on
Windows the border only shows a 1px color you cannot fully control.

**Solution:** normalize.css already applies `-webkit-appearance: textfield` to
`[type="search"]`, which restores most styling control **without** removing the
input's useful behaviors (such as showing past searches). If you still hit limits,
fall back to a regular `[type="text"]` styled to look like a search box.

```css
[type="search"] {
  -webkit-appearance: textfield;
}
```

### Issue: `<button>` text is blue on iOS

**Cause:** iOS Safari's user agent stylesheet colors button text blue; this is a
platform default outside the elements normalize.css resets (reported in issue
#886).

**Solution:** Set the color explicitly:

```css
button {
  color: inherit;
}
```

### Issue: Buttons/inputs show a 2px border-radius in Microsoft Edge

**Cause:** Edge applies a small default border-radius to native controls (issue
#838). normalize.css does not reset `border-radius` on buttons.

**Solution:** Zero it yourself if your design needs square corners:

```css
button, input {
  border-radius: 0;
}
```

### Issue: A Content-Security-Policy blocks my inline `<style>`/`<link>`

**Cause:** Strict CSP setups require a `nonce` (or hash) on style sources (issue
#908). normalize.css is just a stylesheet — it has no special CSP handling.

**Solution:** Serve it as an external file and allow that origin in your
`style-src`, or add the appropriate `nonce` to the `<link>`/`<style>` per your CSP
configuration. There is nothing normalize-specific to change.

### Issue: `<progress>` or `[type="range"]` looks vertically misaligned

**Cause:** Browsers disagree on the baseline of these controls (issue #904).
normalize.css sets `progress { vertical-align: baseline }`, which helps but does
not cover every range-slider quirk.

**Solution:** Set an explicit `vertical-align` (e.g. `middle`) on the control where
the alignment matters to your layout.

> [!TIP]
> For any element you find rendering oddly, first check
> [Section 5](#5-what-it-normalizes--reference) to see whether normalize.css is
> already touching it. If it is not listed there, the behavior is coming from the
> browser's own user-agent stylesheet, and you should override it in your CSS.

---

## 9. FAQ

**Q: Do I still need normalize.css in 2025-era browsers?**
It remains useful for the rules that apply to *all* browsers — form-control font
inheritance, `sub`/`sup` line-height, the `abbr` underline, consistent
`monospace` sizing — even if the Internet-Explorer-specific fixes matter less to
you. Many projects include it (or a fork of it) by habit because it is tiny and
harmless.

**Q: Will it conflict with my CSS framework?**
No. It only sets element-level defaults. Load it before your framework and your
own styles, and both will override it where they specify rules.

**Q: Does it include any JavaScript?**
No. normalize.css is a single CSS file with zero scripts and zero dependencies.

**Q: Is there a minified version?**
The project does not publish one (issue #911). Run the file through any CSS
minifier or your bundler to produce `normalize.min.css` yourself.

**Q: Should normalize.css go before or after my own CSS?**
Before. It is a baseline; your styles are meant to override it.

**Q: It removed my body margin — is that a bug?**
No. `body { margin: 0 }` is the one intentional layout opinion in the file. Add
the margin back in your own CSS if you want it.

**Q: Why is `monospace` written twice in the `pre`/`code` rule?**
That is a deliberate hack that fixes font-size inheritance and scaling for
preformatted/monospace text across browsers. It is not a typo.

**Q: Can I delete the Internet Explorer rules?**
If you truly do not support IE, you can fork the file and remove the rules whose
comments name only IE. Keep the all-browser rules — they still apply to modern
engines.

**Q: How do I customize a normalized element?**
Write your own rule for it in a stylesheet that loads after normalize.css. See
[Section 6](#6-customizing-and-extending).

**Q: Is the project still actively maintained?**
The latest release is **8.0.1 (November 2018)**, and the community has asked about
maintenance status (issue #880). Treat v8.0.1 as a stable, frozen baseline. It
continues to work because it targets long-standing browser behaviors, but do not
expect new releases. See the Admin Guide's "Maintenance & Known Issues" section
for a fuller picture.

**Q: What license is it under?**
MIT — free to use, modify, and redistribute, including commercially. Keep the
license header comment in the file.

**Q: How do I verify it loaded?**
Open your page in a browser, inspect `<body>`, and confirm its computed `margin`
is `0`. The included `test.html` in the repo also exercises every normalization
visually.

---

## 10. Reference

### 10.1 Package facts

| Field | Value |
|-------|-------|
| Name | `normalize.css` |
| Version | `8.0.1` |
| Description | A modern alternative to CSS resets |
| Main / Style entry | `normalize.css` |
| License | MIT |
| Dependencies | None |
| Published files | `normalize.css`, `LICENSE.md` |
| Homepage | `https://necolas.github.io/normalize.css` |

### 10.2 The eight sections at a glance

| # | Section | Elements covered |
|---|---------|------------------|
| 1 | Document | `html` |
| 2 | Sections | `body`, `main`, `h1` |
| 3 | Grouping content | `hr`, `pre` |
| 4 | Text-level semantics | `a`, `abbr[title]`, `b`, `strong`, `code`, `kbd`, `samp`, `small`, `sub`, `sup` |
| 5 | Embedded content | `img` |
| 6 | Forms | `button`, `input`, `optgroup`, `select`, `textarea`, `fieldset`, `legend`, `progress`, `[type="checkbox"]`, `[type="radio"]`, `[type="number"]`, `[type="search"]`, file-upload button |
| 7 | Interactive | `details`, `summary` |
| 8 | Misc | `template`, `[hidden]` |

### 10.3 Versioning and upgrades

The project follows semantic versioning with one unusual twist: because *any*
change to a CSS rule changes how pages render, **every rule change is a major
version bump**. There are effectively no "minor" releases — only major (rule
changes) and patch (changes with no rendering impact). This is why pinning a
specific version matters: upgrading across a major version may visibly shift your
baseline styling, so test after upgrading.

### 10.4 Setup checklist

- [ ] Installed normalize.css (npm, CDN, or download)
- [ ] Linked/imported it **before** your own stylesheet
- [ ] Pinned a specific version (`8.0.1`) rather than "latest"
- [ ] Confirmed `body` computed `margin` is `0` in DevTools
- [ ] Re-added the body margin in your own CSS if your design needs it
- [ ] Verified form controls inherit your page font

---

_Generated June 2026 from necolas/normalize.css at fc091cc. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
