sanitize.css
sanitize.css is a global CSS foundation that combines browser normalization with opinionated defaults such as border-box sizing, non-repeating backgrounds, zero body margin, a 1.5 root line height, overflow wrapping, normalized form quirks, vertical-only textarea resizing, collapsed table borders, and navigation-list cleanup. Most element rules use :where() for zero specificity so application styles can override them easily. Optional files separately cover forms, responsive assets, system typography, reduced motion, and legacy system font aliases. Despite the name, it does not sanitize untrusted CSS or HTML and provides no XSS protection.
sanitize.css is a thoughtful, readable baseline for teams that agree with its opinions and test the global result. It is not a security tool, its IE claim conflicts with :where(), and the long gap between npm 13 and newer repository fixes makes pinning and source review essential.
Use it if
- You want a documented global baseline that goes further than standards-only normalization
- Your design system benefits from zero-specificity element defaults that component styles can override cheaply
- You want to opt into separate form, asset, typography, or reduced-motion foundations rather than one monolithic reset
- You support modern browsers and can review every opinionated global rule against your existing UI
- You are looking for a security sanitizer: the package is static CSS and does not parse, filter, or make user-provided markup and styles safe
- Your application already has a reset or component-library baseline: loading both creates competing global assumptions for box sizing, margins, tables, lists, form controls, SVG fill, and media alignment
- You need the README's claimed Internet Explorer 9 support in practice: version 13 wraps most selectors in :where(), which Internet Explorer does not understand, so those entire rules are ignored there
- You want conservative normalization only: sanitize.css deliberately changes developer-facing behavior, including non-repeating backgrounds, root overflow wrapping, navigation list markers, textarea resize direction, and default fieldset borders
- You require npm releases to track repository fixes promptly: version 13.0.0 was published in September 2021, while multiple fixes landed on main in March 2026 and are not part of that package
Setup reality
Install sanitize.css and import the root stylesheet once near the start of your global CSS or application entry. There are no JavaScript dependencies, peer packages, native builds, credentials, or runtime configuration. It is CSS, so a JavaScript import requires bundler CSS handling; a plain browser can use a link element instead. Pin CDN URLs to a version rather than copying the README's floating endpoints into production. The root import does not include forms.css, assets.css, typography.css, reduce-motion.css, system-ui.css, or ui-monospace.css. Add only the optional files whose behavior you have reviewed. forms.css makes controls transparent, inherits typography, adds borders and padding, and replaces the select arrow with a data-URI SVG. assets.css caps several replaced and form elements at 100 percent width. typography.css chooses long system font stacks. reduce-motion.css applies !important timing overrides to every element and pseudo-element when the user asks for reduced motion; that is broad enough to break components that depend on transitionend or animationend, and the repository has an open concern about harmful cases. The published 13.0.0 root file is 7,381 bytes before transfer compression and contains global selectors. Most rules use :where() to carry zero specificity, but universal rules for box-sizing and background-repeat do not, and typography.css uses ordinary html and element selectors. Import order still matters when specificity ties. A CSS layer can make the baseline's cascade position explicit, but confirm your build tool preserves layer semantics. Audit screenshots, focus behavior, printed output, native controls, rich-text content, and navigation lists. In particular, the inserted zero-width pseudo-element on nav list items has an open flexbox complaint. The documentation on the main branch includes 2026 changes that are absent from npm 13.0.0, so inspect the installed files rather than assuming the website always describes the published artifact exactly.
Patterns
Load the core foundation from JavaScriptimport-core-styles
import 'sanitize.css';
import './app.css';Import sanitize.css before application styles so equal-specificity rules in app.css come later. Your bundler must be configured to process CSS imports.
Load the foundation from global CSSimport-from-css
@import 'sanitize.css';
/* Project tokens and components follow. */
@import './tokens.css';
@import './components.css';Package import resolution depends on the CSS build tool. The README's webpack tilde form is unnecessary in many current toolchains.
Use a version-pinned browser stylesheetload-pinned-cdn
<link rel="stylesheet" href="https://unpkg.com/sanitize.css@13.0.0/sanitize.css">A pinned URL prevents an upstream release from changing every page unexpectedly. A CDN remains an availability and policy dependency.
Opt into the separate forms baselinenormalize-form-controls
import 'sanitize.css';
import 'sanitize.css/forms.css';forms.css changes borders, padding, backgrounds, inherited fonts, range and color inputs, and select appearance. It is not included by the root import.
Keep common assets within their containerconstrain-page-assets
import 'sanitize.css';
import 'sanitize.css/assets.css';In npm 13.0.0 this affects iframe, img, input, video, select, and textarea. Newer main-branch documentation may describe a different selector list.
Apply the optional system font stacksuse-system-typography
import 'sanitize.css';
import 'sanitize.css/typography.css';typography.css uses ordinary html, code, kbd, samp, and pre selectors rather than zero-specificity :where(), so overrides need normal cascade planning.
Load the reduced-motion policyrespect-reduced-motion
import 'sanitize.css/reduce-motion.css';Version 13 applies !important duration and delay overrides globally. Test components that rely on animation or transition completion events before enabling it.
Put sanitize.css in a low-priority layerplace-in-cascade-layer
@layer reset, tokens, components, utilities;
@import 'sanitize.css' layer(reset);
@import './tokens.css' layer(tokens);
@import './components.css' layer(components);Layer ordering can make the baseline predictable even when selector specificity differs. Verify that your target browsers and CSS processor preserve import layers.
Replace an opinionated root defaultoverride-root-defaults
:root {
line-height: 1.4;
overflow-wrap: normal;
tab-size: 2;
}The core root declarations use :where(:root), which has zero specificity, so a later ordinary :root rule overrides them cleanly.
Restore list styling inside navigationrestore-navigation-markers
nav ul.docs-tree {
list-style: disc;
padding-inline-start: 1.5rem;
}
nav ul.docs-tree > li::before {
content: none;
float: none;
}The core sheet removes nav list markers and inserts a zero-width pseudo-element for Safari semantics. Override both when a navigation tree needs visible bullets or flex-safe children.
Opt a component back into repeating backgroundsrestore-repeating-background
.checkerboard {
background-image: var(--checker-pattern);
background-repeat: repeat;
}The universal core rule sets background-repeat: no-repeat on every element and pseudo-element, so repeating patterns must opt back in.
Inspect the exact CSS shipped by npmaudit-installed-version
npm ls sanitize.css
node -e "console.log(require.resolve('sanitize.css/sanitize.css'))"The website follows repository main, while npm 13.0.0 predates 2026 source changes. Review the resolved file when a documented rule seems absent.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| normalize.css | npm | You want browser bug corrections that stay closer to CSS specifications and add fewer opinions |
| modern-normalize | npm | You target modern browsers and want a compact maintained normalization baseline |
| ress | npm | You want an opinionated reset with broad element coverage and a different set of defaults |
| destyle.css | npm | You want a stronger blank-slate reset and intend to restyle nearly every element yourself |