sodcalculator

10 Tech How-To

CSS Reset & Design System: How to Combine Them

Guide 10-20478 · Updated · Step by step

A CSS reset and a design system work together when the reset handles browser inconsistencies and the design system handles consistent styling decisions. You use the reset as a foundation layer that normalizes default styles, then build your design system’s tokens, components, and utilities on top of it. This article explains how to structure that relationship, what each layer should contain, and how to avoid common conflicts.

Background: Why Both Exist

Browsers apply their own default styles to HTML elements—paragraphs get margins, headings get bold and specific font sizes, lists get padding and markers. These defaults differ slightly between browsers and have changed over time. A CSS reset removes or neutralizes these defaults so you start from a clean slate. Early resets (like Eric Meyer’s) zeroed out all margins and padding. Modern resets (like Normalize.css) take a gentler approach, preserving useful defaults while making them consistent across browsers.

A design system, on the other hand, is a complete set of standards for visual and functional design: color palettes, typography scales, spacing units, component patterns, and usage guidelines. It answers questions like “what does a button look like?” and “how much space goes between cards?” While a reset deals with the browser’s default styles, a design system deals with your brand’s intentional styles.

The two serve different purposes, but they both affect the same CSS properties. Without a clear strategy, they can fight each other—your reset might override a component’s padding, or your design system might rely on a default that the reset removed.

How They Work Together

The key is to treat them as separate layers in a cascade, with the reset at the bottom and the design system above it. In practice, this means:

  • Reset first: Load your CSS reset before any design system styles. This ensures the reset’s job—normalizing defaults—happens first.
  • Design tokens next: CSS custom properties (variables) for colors, spacing, typography, and other core values. These are the raw materials of your design system.
  • Base element styles: Styles for plain HTML elements (headings, paragraphs, links) that use your tokens. This is where you set your typography scale, link colors, and default spacing.
  • Components and utilities: The actual UI components (buttons, cards, forms) and any utility classes. These should be the most specific and come last.

The reset ensures that all elements start from the same baseline. Your design system then applies your chosen styles on top of that baseline. Since the reset has lower specificity (usually just element selectors) and comes first, your design system’s styles naturally win in the cascade.

For example, a reset might set all margins to 0. Your design system then defines a spacing scale (e.g., –space-1: 4px; –space-2: 8px) and applies margins to components using those variables. Without the reset, you’d be fighting browser defaults that are already there.

Choosing the Right Reset

You have several options, each with a different philosophy:

  • Full reset (Eric Meyer’s): Removes all default styling. You must explicitly style everything. Gives you maximum control but requires more work.
  • Normalize.css: Preserves useful defaults while making them consistent across browsers. Less aggressive, so you don’t have to redefine everything.
  • Sanitize.css: A modern alternative to Normalize that also includes some opinionated defaults (like box-sizing: border-box).
  • Custom minimal reset: Just a few rules that address the most common inconsistencies (e.g., box-sizing, margin removal, image max-width).

For a design system, Normalize.css or a custom minimal reset is often the better choice. A full reset forces you to redefine every default, which can bloat your CSS if you’re not careful. Normalize keeps useful defaults (like list-style for lists) so your design system only needs to override what’s actually different.

Common Problems and Solutions

When the reset and design system conflict, you’ll see unexpected spacing, missing list bullets, or buttons that look different across browsers. Here are the most common issues:

  • Reset overrides component styles: If your reset uses a high-specificity selector (like * { margin: 0; }) and your component uses a class, the reset can win if it comes later in the cascade. Solution: always load the reset first, and avoid universal selectors in the reset.
  • Box-sizing mismatch: If your reset doesn’t set box-sizing to border-box, but your design system assumes it does, padding will break your layout. Solution: include box-sizing: border-box in your reset or base layer.
  • Focus styles removed: Some resets remove outline, which kills keyboard accessibility. Solution: add explicit focus-visible styles in your design system.
  • List styles missing: If your reset removes list-style, but your design system doesn’t re-add it, all lists lose their bullets. Solution: either keep list-style in the reset or define it in your base element styles.

The fix is to audit your reset and design system together. Check which properties the reset changes, and ensure your design system explicitly defines those properties for the elements you use.

Integration with Modern CSS

Modern CSS features make the reset/design system relationship cleaner:

  • CSS Custom Properties: Define your design tokens as variables in :root. The reset doesn’t need to touch them, and components can reference them.
  • Cascade Layers: Use @layer to explicitly order reset, base, components, and utilities. This gives you control over the cascade without relying on source order or specificity.
  • :where() and :is(): Use :where() for low-specificity resets, so any component style can easily override them.

For example, with cascade layers, you can write:

@layer reset, base, components, utilities;

Then each layer takes precedence in that order. This makes it impossible for the reset to accidentally override a component, regardless of specificity.

Practical Implementation Steps

To make them work together in a project:

  1. Install a reset (like Normalize.css) or write a minimal custom one. Ensure it’s the first CSS loaded.
  2. Define your design tokens as CSS custom properties in :root (colors, fonts, spacing, etc.).
  3. Write base element styles that apply those tokens to plain HTML elements (body, h1-h6, p, a, ul, etc.).
  4. Build your components using classes, referencing the tokens. Keep component styles in separate files or sections.
  5. Test in multiple browsers to ensure consistency. Use browser dev tools to inspect computed styles and see if any reset rules are interfering.

If you’re using a framework like Tailwind or Bootstrap, the same principle applies: the framework’s preflight/reset is the foundation, and your design system (custom utilities, components) builds on it.

Frequently Asked Questions

Should I use a CSS reset or a design system?

Both. They solve different problems. A reset handles browser inconsistencies; a design system handles your brand’s visual consistency. You need both for a robust, maintainable stylesheet.

Can I skip the reset if I use a design system?

Technically yes, but you’ll likely run into cross-browser inconsistencies. Without a reset, your design system must account for each browser’s default styles, which is extra work and error-prone. A reset saves time in the long run.

What’s the difference between a reset and Normalize.css?

A reset removes all default styling, while Normalize.css preserves useful defaults and makes them consistent across browsers. Normalize is generally recommended for design systems because it reduces the amount of re-styling you need to do.

How do I prevent the reset from overriding my component styles?

Load the reset first, keep its specificity low (avoid universal selectors), and use cascade layers if you have them. Also, make sure your component styles use classes or more specific selectors than the reset.

Does box-sizing: border-box belong in the reset or the design system?

It’s a global default, so it belongs in the reset or a base layer. Setting it globally ensures all elements use border-box, which makes layout calculations more predictable. Most modern resets include it.

Can I use a CSS framework’s reset with my own design system?

Yes. Frameworks like Bootstrap and Tailwind include their own resets (Preflight in Tailwind). You can build your design system on top of that, as long as you understand what the framework’s reset does and override it appropriately.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →