The Complete CSS !important Interactive Tutorial

!important is CSS’s “override switch”… but it’s not a magic wand. It can save your day, or it can quietly ruin your future weekends (because now you have to fight your own CSS later).

In this tutorial, you’ll learn how !important actually fits into the cascade, how it interacts with specificity, why it sometimes “doesn’t work”, and what to do when inline styles enter the chat.

What !important is (and isn’t)

When you add !important to a declaration, you are telling the browser: “If there’s a conflict for this property, prefer this declaration over normal ones.”

  • It affects only that declaration (that property), not the whole selector.
  • It does not increase selector specificity. It changes the “importance” step in the cascade.
  • It can still be overridden (by another !important declaration with greater specificity, or later source order if specificity ties).
.note {
  background: #ffe9a8 !important;
}
  
.note {
  background: #c9f0ff;
}
  
.note {
  background: #c9f0ff !important;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrapper {
  display: grid;
  gap: 12px;
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 16px;
}

.note {
  padding: 14px 16px;
  border: 2px solid #111;
  border-radius: 14px;
}

.hint {
  font-size: 14px;
  opacity: 0.85;
}
  
This box is .note
Try each snippet. Notice: !important only affects background.

In snippet 1, the background “wins” even if another normal rule exists. In snippet 3, the later rule also uses !important, so now we’re back to normal CSS tie-breakers (specificity, then source order).

The cascade in plain English

When two declarations try to set the same property on the same element, the browser decides which one wins using a predictable order. Here’s the beginner-friendly version:

  1. Origin: where the CSS comes from (browser default, your CSS, extensions, etc.).
  2. Importance: normal vs !important.
  3. Specificity: how “targeted” the selector is.
  4. Source order: if everything ties, the later rule wins.

The biggest takeaway: !important is not “above everything”. It’s “above normal declarations” within the same origin/importance context, and it still participates in specificity comparisons against other !important rules.

Learn more about the cascade in the CSS Cascade Interactive Tutorial.

CSS specificity (the scoreboard)

Specificity is a way to compare selectors. A helpful mental model is a 3-part score:

  • IDs (greatest specificity among these three): #header
  • Classes / attributes / pseudo-classes: .card, [data-x], :hover
  • Elements / pseudo-elements: button, h2, ::before

The selector with the greater score wins. If the score is equal, the later rule wins.

Learn more about specificity in the CSS Specificity Interactive Tutorial.

a {
  color: #2c5cff;
}
.link {
  color: #b31d1d;
}
#nav .link {
  color: #0a7a2f;
}

#nav a.link {
  color: #7a1bb3;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 16px;
  border: 2px solid #111;
  border-radius: 14px;
  display: grid;
  gap: 10px;
}

.small {
  font-size: 14px;
  opacity: 0.8;
}
  

  

Play with the selectors above, delete some then CTRL-Z them back in place. Notice how a is weaker than .link, and how adding an ID selector (#nav) makes the rule much harder to beat.

Using !important responsibly

The most common “good” uses of !important are:

  • Utility override classes like .is-hidden, .sr-only, .no-scroll.
  • Third-party CSS you can’t change (temporary patch until you can fix properly).
  • Debugging: quickly prove whether “this property is being overridden”.
.card {
  display: block;
}
  
.is-hidden {
  display: none !important;
}
  
.is-hidden {
  display: none !important;
}

.card {
display: block;
} 
*,
::before,
::after {
  box-sizing: border-box;
}

.grid {
  display: grid;
  gap: 12px;
  font-family: ui-sans-serif, system-ui, sans-serif;
}

.card {
  padding: 14px 16px;
  border: 2px solid #111;
  border-radius: 14px;
  background: #f2f2f2;
}

.note {
  font-size: 14px;
  opacity: 0.85;
}
  
Snippet 2 uses display: none !important. Snippet 3 shows that even if .card appears later, the !important declaration still wins.

Used like this, !important acts like a deliberate “escape hatch” with a clear, narrow goal.

CSS !important override: how to beat it

Here’s the rule you’ll use 99% of the time:

  • If a declaration has !important, you usually need another declaration with !important to compete.
  • When both declarations are !important, specificity decides.
  • If specificity ties, later source order wins.
.button {
  background: #1e6bff !important;
}
  
.button {
  background: #1e6bff !important;
}

.page .button {
background: #0a7a2f !important;
} 
.button {
  background: #1e6bff !important;
}

.page .button {
  background: #0a7a2f;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.page {
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 16px;
  display: grid;
  gap: 12px;
}

.button {
  border: 2px solid #111;
  border-radius: 999px;
  padding: 10px 14px;
  cursor: pointer;
}

.small {
  font-size: 14px;
  opacity: 0.85;
}
  
Snippet 2 beats the original !important by using another !important plus a more specific selector. Snippet 3 shows a common mistake: adding specificity but forgetting !important.

The key idea: you don’t beat !important with “normal CSS”. If you want to override it in CSS, you usually need your own !important, and then you must win specificity (or source order).

What about inline styles?

Inline styles (like style="color: red;" in the HTML) behave like they have great specificity. If the inline declaration itself uses !important, it’s effectively “CSS final boss”.

Later in the tutorial you will learn how to use JavaScript to remove or change inline styles, which is often the best solution when you’re fighting an inline !important.

CSS !important not working: common reasons

If you wrote !important and nothing changed, one of these is almost always the reason:

  • You’re changing the wrong property. Example: you try color but the text is inside a child element that has its own color.
  • The element is not the one you think. Example: your selector doesn’t match, or matches a different element.
  • Another rule is also !important and is more specific.
  • The style is inline (or injected later by JavaScript).
  • You’re fighting a different origin (less common, but can happen with extensions or user styles).
  • You’re overriding a shorthand with a longhand (or vice versa) in a way you didn’t expect.
.card {
  color: #b31d1d !important;
}
  
.card {
  color: #b31d1d !important;
}

.card strong {
color: #0a7a2f;
} 
.card {
  color: #b31d1d !important;
}

.card strong {
  color: #0a7a2f !important;
}
  
.card {
  color: #b31d1d !important;
}

.card strong {
  color: inherit;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.card {
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 16px;
  border: 2px solid #111;
  border-radius: 14px;
  background: #f7f7f7;
}

.small {
  margin-top: 8px;
  font-size: 14px;
  opacity: 0.85;
}
  
This word can be styled separately
Snippet 1 changes the card’s color. Snippet 2 shows a child rule can still set its own color. Snippet 3 adds !important to the child. Snippet 4 uses inherit to “force” inheritance.

Debug habit: in DevTools, click the element and look at the “Computed” styles. The browser will literally show you which rule won and which ones were crossed out.

CSS !important class: myth and reality

You can’t make a class “more important” as a selector by adding !important somewhere. Why? Because !important is not part of the selector. It belongs to a declaration.

What you can do is:

  • Add a more specific selector for the same class (for example, include a parent class).
  • Use harmless specificity “boosters” like :not(#incspec) (a common trick because it adds ID-level specificity without matching anything).
.badge {
  background: #ddd;
}
  
.badge {
  background: #ddd;
}

.widget .badge {
background: #c9f0ff;
} 
.badge {
  background: #ddd;
}

.badge:not(#incspec) {
  background: #ffe9a8;
}
  
.badge {
  background: #ddd !important;
}

.badge:not(#incspec) {
  background: #ffe9a8 !important;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.widget {
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 16px;
  border: 2px solid #111;
  border-radius: 14px;
  display: grid;
  gap: 10px;
}

.badge {
  display: inline-block;
  padding: 6px 10px;
  border: 2px solid #111;
  border-radius: 999px;
}
  
Badge
Snippet 3 uses .badge:not(#incspec) as a specificity booster. Snippet 4 shows how this matters when !important is involved on both sides.

A caution: specificity hacks are powerful, but they are also a signal you may want to refactor your CSS architecture. Use them as a last resort, not as a lifestyle.

CSS !important inline: the “remove it with JavaScript” moment

Inline styles are applied directly on the element. When you see something like: <div style="color: red;"> it often beats your stylesheet rules.

Even worse: <div style="color: red !important;"> is very hard to override with CSS alone.

In practice, if inline styles are being injected by JavaScript (or a page builder, or a widget), the most reliable fix is: remove or change the inline style.

JavaScript example: remove one inline property

// Remove only the inline "color" property:
const el = document.querySelector('.target');
el.style.removeProperty('color');

JavaScript example: remove the entire style attribute

// Remove the whole style attribute (all inline styles):
const el = document.querySelector('.target');
el.removeAttribute('style');

JavaScript example: remove an inline !important value

// If a script set: el.style.setProperty('color', 'red', 'important')
const el = document.querySelector('.target');
el.style.removeProperty('color');

If you’re working with a builder/plugin that keeps re-inserting inline styles, you’ll want to fix the source (the builder settings, the plugin option, or the script) rather than playing whack-a-mole.

.target {
  color: #0a7a2f;
}
  
.target {
  color: #0a7a2f !important;
}
  
.target {
  color: #0a7a2f !important;
}

#wrap .target {
color: #7a1bb3 !important;
} 
*,
::before,
::after {
  box-sizing: border-box;
}

#wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 16px;
  border: 2px solid #111;
  border-radius: 14px;
  display: grid;
  gap: 10px;
}

.target {
  padding: 12px 14px;
  border: 2px solid #111;
  border-radius: 12px;
  background: #f2f2f2;
}

.small {
  font-size: 14px;
  opacity: 0.85;
}
  
I have an inline color with !important.
Switch to the HTML view to see the inline styles. CSS can struggle here. In real projects, removing the inline style with JavaScript (or fixing the source) is the practical solution.

Practical patterns and what to do instead

Pattern 1: Use utility overrides intentionally

  • Good: .is-hidden { display: none !important; }
  • Good: .no-scroll { overflow: hidden !important; }
  • Good: .sr-only patterns for accessibility (often use !important for reliability)

Pattern 2: Keep specificity low by default

If you avoid overly specific selectors like #page .sidebar ul li a, you’ll need fewer overrides later. Prefer class-based, reusable selectors like .nav-link.

Pattern 3: Fix the source of inline styles

Inline styles are often produced by:

  • A page builder setting
  • A third-party component script
  • Your own JavaScript doing element.style...

When possible, move those values into a class and toggle the class instead of writing inline styles.

Avoid “!important wars”

If you find yourself stacking !important everywhere, it’s usually a sign of:

  • Overly specific selectors earlier in the codebase
  • CSS rules that are doing too much (components not isolated)
  • Styles applied inline by tools/scripts

The healthiest long-term fix is often: refactor toward clearer layers (base → components → utilities), and keep your selectors simple and predictable.

Quick reference cheat sheet

  • !important affects a declaration, not selector specificity.
  • To override a !important rule in CSS, you usually need your own !important.
  • If both are !important, specificity wins.
  • Inline styles are very strong; inline + !important is best handled by removing/changing it (often with JavaScript).
  • If !important “doesn’t work”, check: selector match, element target, competing !important, inline styles, inheritance.