A third-party widget sets its background colour through the style attribute on the element. Why can't a more specific CSS selector override it, and what can?
answer
- it has no selector to score
- cascade ranks it, not specificity
- importance is compared earlier
- only one thing outranks it
- important inline ends the argument
basics
~20 sThe style attribute is not scored by specificity at all: the cascade ranks its declarations above every normal rule in your stylesheets, however specific the selector. Only a declaration marked !important beats a normal inline one.
solid answer
~40 sSpecificity only scores selectors, and a declaration in the `style` attribute was never matched by one — it is attached directly to the element. The cascade handles it as its own step, ranking style-attribute declarations above all normal author declarations, so piling on IDs and classes can never reach it. What does reach it is importance: a declaration marked `!important` in your stylesheet outranks a normal inline declaration, because importance is compared before specificity ever runs. The exception is an inline declaration that is itself `!important` — typically written by a script — which nothing in an author stylesheet can beat. In practice the durable fix is to stop the widget emitting the inline style, and `!important` is the escape hatch when you cannot.
code
html · 5 lines<div class="widget" id="w" style="background-color: #c00">Widget</div>
<style>
#w.widget { background-color: #00c; } /* 1-1-0 — still loses */
.widget { background-color: #fff !important; } /* 0-1-0 — wins */
</style>go deeper
Know that a style attribute beats your stylesheet rules no matter how specific they look, and that !important is the usual way to override it.
Explain the mechanism: the style attribute has no selector to score, so the cascade ranks it as its own step above normal rules, and importance is compared before specificity runs at all.
Show judgment about which tool to reach for — diagnose where the winning declaration came from, and treat !important as a bounded response to code you do not own rather than a general fix.
Own the policy: decide when a third-party widget is worth an override at all versus wrapping or replacing it, and set the rule for whether !important is ever permitted in first-party stylesheets.
## Why specificity has nothing to say here Specificity is computed from selector text: count the IDs, the classes, the types. A declaration written in an element's `style` attribute has no selector, so there is nothing to count. It is not a very high specificity — it has none. Instead, the cascade gives style-attribute declarations their own rank. When it sorts competing declarations, it puts normal declarations from the `style` attribute above every normal declaration that came from a stylesheet, regardless of how those stylesheet rules were written. `#page #main #widget.widget.widget` and `.widget` lose to the inline value in exactly the same way, for exactly the same reason: they lost at an earlier step and their triples were never compared. This is the practical answer to "my override doesn't work and I've already added three IDs". Adding a fourth changes nothing. Once you see the value shown as an element style rather than as a matched rule, specificity is no longer the lever. ## The lever that does work Importance is compared before specificity. A declaration marked `!important` in your stylesheet outranks a normal declaration from the `style` attribute: ```css .widget { background-color: #fff !important; } ``` ```html <div class="widget" style="background-color: #c00">…</div> ``` The white background wins. Note what this is *not*: `!important` did not raise the rule's specificity. Specificity is unchanged at `0-1-0`; the declaration simply won a step that happens earlier. If a second important declaration in your stylesheet also targets the element, then specificity comes back into play to choose between the two important ones. ## Where the escape hatch stops working If the inline declaration is itself important — `style="background-color: #c00 !important"`, or set from script with a priority argument — an author stylesheet has nothing left. Important inline declarations outrank important stylesheet declarations, and there is no author-origin construct above them. At that point the fix is not CSS at all: change the markup, configure the widget so it stops writing the style, or remove the property from the element after the widget runs. ## Why this shows up so often Inline styles are what libraries write when they need a computed value — a measured height, a positioned popover offset, a theme colour pulled from a config object. They are legitimate for genuinely dynamic values and hostile to theming, because they sit above the entire stylesheet by construction. That is also why an `!important` in your own stylesheet is a reasonable, bounded response to *someone else's* inline style, and a much worse idea inside your own codebase, where it starts an escalation your future overrides have to match. ## How to reason about it on the spot When a value refuses to change, first classify where the winning declaration came from: 1. **From a stylesheet rule** — then specificity or source order is the story, and you can win by scoring higher or by ordering later. 2. **From the `style` attribute** — then specificity is irrelevant, and your options are `!important` or removing the inline declaration. 3. **From an important inline declaration** — then the author origin has run out of moves and the fix belongs in the markup or the script. Making that classification explicit is what an interviewer is listening for. The weak answer keeps reaching for more selectors; the strong one names the step of the cascade that decided the outcome, and only then picks a tool. ## A note on what you should *prefer* Winning is not the same as being right. Reaching for `!important` against a widget you do not control is defensible; reaching for it because your own two rules collide means the collision is the bug. And an important declaration you add today is a constraint on every override written after it, since the only thing that beats an important author declaration is another important author declaration with a higher-scoring selector.
- If the widget's inline declaration is itself marked !important, what are your options from a stylesheet?None. An important declaration in the `style` attribute outranks important declarations from author stylesheets, so no selector and no `!important` of yours can win. The fix has to happen outside CSS: configure the widget not to write the style, change the markup, or remove the property from the element after the widget has run.
- Does adding !important change a rule's specificity?No. The selector's triple is unchanged; importance is a separate, earlier step in the cascade. Once several important declarations compete, specificity still decides between them — which is why an important rule with a weak selector can be beaten by another important rule with a stronger one.
- Why do libraries write inline styles in the first place if they are so hard to override?Because the value is computed at runtime and cannot be written in a static stylesheet — a measured height, a drag offset, a positioned popover coordinate, a colour from a config object. That is a legitimate use. The problem is only when a library inlines static, themeable values that belong in a class.
saying these in an interview costs you the question
- Says inline styles have a specificity of 1-0-0-0
- Tries to beat an inline style by adding more ID selectors
- Claims !important raises the selector's specificity
- Believes nothing can ever override an inline style
- Thinks a later stylesheet rule can outrank an inline declaration