Reference guide · html-css-js · Published 2026-08-15 · 4 min read
Why CSS rules beat inline styles
CSS rules vs inline styles: maintainability, specificity, caching and media queries, plus when inline style attributes are fine.
- ·Four differences
- ·When inline is fine
- ·Comparison table
Why a stylesheet rule beats an inline style
Inline styles, the style="..." attribute written directly on an element, work. They also fight everything around them. The cascade exists to be the single place where styling is managed, and inline styles remove the element from it.
The four differences that matter:
- Maintainability. A class is edited in one file and applies to every element that uses it. Inline styles are edited per element, and the change is a search-and-replace pass over markup instead of one rule.
- Specificity in a separate lane. Inline styles win by precedence over the whole specificity scale, including an ID selector:
style="color: red"beats#nav { color: blue }, so an inline style can never be overridden by the stylesheet without the!importantescape hatch, which adds the costs the specificity article documents. - Caching. Styles shipped in a
.cssfile are cached across pages; the same styling spelled inline is downloaded again in every page's HTML. - Media queries and hover. A CSS rule can respond to viewport width, theme and hover state because those are document-level conditions. An inline style is a fixed value that never changes, so a responsive design cannot be built on inline styles.
The comparison table
| Concern | Inline style | Stylesheet class |
|---|---|---|
| Change one value | Edit every element | Edit one rule |
| Override later | Needs !important | Normal cascade wins |
| Caching across pages | Downloaded each page | Cached once |
| Media query support | None | Full |
| Priority | Beats every specificity | Ordered by cascade |
| SSR and email | Common | Not always available |
Where inline styles are fine
There are a handful of places where a single computed value genuinely belongs on the element:
- Dynamic values from JavaScript. A progress bar whose width is set by data is the canonical case; the style must reflect runtime state, and a CSS custom property set from JS is the cleaner sibling.
- One-off layout from data: a background image URL, a rotation, a counter, all one-time values that a class would need to enumerate.
- Emails: most email clients strip stylesheet support, so legacy clients by design require inline styles.
- CMS output you cannot touch: a page builder that writes inline by design, acceptable when the rest of the site uses classes.
The rule: if the value is data, inline is fine. If the value is a design decision, a class is better. The design decision is exactly what a team needs to override later.
CSS custom properties: the inline-adjacent middle ground
When a dynamic value still needs to flow through the cascade, set a custom property inline and pull it in the stylesheet:
<div class="bar" style="--fill: 62%"></div>
.bar::before { width: var(--fill); }
The width is dynamic, the styling stays in the stylesheet, and the custom property keeps the specifics readable. This is the pattern that covers most "could we inline it" cases, including theming and data-driven layout.
The rule that keeps inline styles honest
If an inline style must exist:
- Keep it one line.
- Use it for data only, never for grid or responsive layout.
- Never write an inline style that a theme needs to override; the accessibility basics article lists the ones a theme (high contrast, dark mode) will fight.
The refactor direction is usually the same: move conventional styling to the stylesheet, and keep inline only the genuinely dynamic values. When margin and padding bugs appear near the refactor, the box model article explains the spacing half.