October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk6 min

CSS Specificity: How It Works and How to Avoid Common Issues

CSS specificity is a cascade tie-breaker, not a total score. Learn the three-column calculation, modern selector exceptions, cascade layers, and a practical debugging workflow.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

CSS specificity is a tie-breaker in the cascade, not a universal strength score. The browser considers earlier cascade rules—such as whether a rule applies, its origin, importance, and layer—before comparing selector specificity. When specificity does decide the winner, compare three columns from left to right: IDs, class-like selectors, then types.

Where specificity fits in the cascade

Specificity only compares declarations that remain in contention after earlier cascade criteria have been considered. A selector can look more specific and still lose because its declaration is less important, comes from a lower-precedence origin or layer, or does not apply to the element. After specificity, scope proximity and then source order can resolve a remaining tie. See MDN’s introduction to the CSS cascade.

A useful diagnostic sequence is: check whether the rule applies, compare origin and importance, compare layer precedence, then specificity, scope proximity, and source order. The full ordering has details beyond this summary; the key is not to start by counting selector parts.

How to calculate specificity

Write specificity as three columns, often called ID-CLASS-TYPE. Compare the columns from left to right. This is lexicographic comparison, not ordinary arithmetic: do not add the values into a total or read them as a decimal number.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • ID column: ID selectors such as #app.
  • Class-like column: class selectors, attribute selectors, and pseudo-classes, such as .notice, [type="warning"], and :hover.
  • Type column: type selectors and pseudo-elements, such as p and ::before.

Combinators—including descendant whitespace, >, +, and ~—and the universal selector * add no weight. The rules and examples below follow MDN’s specificity guide and the Selectors Level 4 specification.

Selector Specificity Why
#app .notice[type="warning"] p::before 1-2-2 One ID; one class and one attribute; one type and one pseudo-element.
.card p 0-1-1 One class and one type.
#card p 1-0-1 One ID and one type; its ID column outranks the class column in .card p.
html body main input 0-0-4 Four types.
:root input 0-1-1 :root is a pseudo-class, so its class-like column is compared before the type column.

Thus :root input outranks html body main input on specificity, despite having fewer selector components. For a comma-separated selector list, each matching branch has its own specificity; the branch that matches the element determines the specificity for that match. Do not add the branches together.

Modern pseudo-classes that change the calculation

:is(), :not(), and :has()

These pseudo-classes do not add a fixed pseudo-class weight of their own. Instead, their specificity is based on the most-specific selector in their argument list—even if a less-specific branch is the one that matches. For example, :is(.notice, #app) p has specificity 1-0-1: the #app argument supplies the ID column, and p supplies the type column. An ID tucked into one of these argument lists can therefore make a selector unexpectedly difficult to override.

Rank #2
Pocket Ref
  • Author: Thomas Glover
  • 864 pages
  • 3.2" x 5.4", softbound
  • (Also available in Desk Size item 2072)

:where()

:where() and all of its arguments contribute zero specificity. For example, :where(#app) p has specificity 0-0-1, not 1-0-1. This is useful for scoped defaults that should remain easy for application or downstream styles to override.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For the formal selector rules, consult the Selectors Level 4 specification and MDN’s specificity reference.

How cascade layers affect a specificity conflict

Layers set precedence between groups of declarations; they do not change a selector’s specificity. Within the same origin and importance, normal declarations in a later layer beat those in an earlier layer. Normal declarations outside explicit layers outrank normal declarations inside them. For important declarations, layer ordering reverses. MDN explains the practical ordering in its cascade layers guide; the behavior is specified in CSS Cascading and Inheritance Level 5.

You can use layers to establish intended precedence among resets, third-party styles, components, themes, and overrides without escalating selectors. For example, declare the order once, then place related rules in the appropriate layer:

@layer reset, vendor, components, theme, overrides;

@layer vendor {
  .button { color: black; }
}

@layer overrides {
  .button { color: rebeccapurple; }
}

For normal declarations, the later overrides layer wins here even though both selectors have the same specificity. Keep the relevant declarations in layers if you want that layer ordering to govern their conflict; an unlayered normal rule outranks layered normal rules in the same origin.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why a more-specific rule can lose

  • An earlier cascade criterion decides the result. Importance, origin, or layer precedence is considered before specificity. A higher-specificity declaration can lose if it is in a lower-precedence position.
  • The apparent contenders do not actually compete. One selector may not match the same element, the property may differ, or a media, supports, or other conditional rule may not apply.
  • A pseudo-class argument adds hidden weight. An ID in :is(), :not(), or :has() may raise the selector’s specificity.
  • Inline style is being compared as though it were a selector. Inline styles have special cascade precedence relative to stylesheet rules of the same importance and origin context. They are not a fourth specificity column, and ordinary three-column arithmetic does not let a stylesheet selector beat an inline normal style.
  • Specificity ties. Scope proximity can decide a conflict before source order. If scope proximity also ties, later source order may win.
  • !important changes the comparison. It changes cascade priority; it is not a specificity boost. Adding it just to overpower a selector mismatch often makes later maintenance harder.

A practical workflow for diagnosing a losing rule

  1. Inspect the exact element and property. In browser developer tools, select the element and find the declaration currently applied and the crossed-out declarations. Note each rule’s stylesheet location and selector.
  2. Verify that both rules can apply. Confirm they target the same element and property, check any conditional rules, and make sure the expected stylesheet loaded.
  3. Compare the cascade position before counting. Check importance and origin, then layer precedence. A crossed-out declaration with a higher-specificity selector can still lose at this stage.
  4. Calculate the remaining selectors. Count each selector’s ID, class-like, and type components separately. Inspect :is(), :not(), and :has() arguments for specificity that may not be obvious from the matching branch.
  5. Resolve a tie in order. Check scope proximity when scopes are involved, then source order.
  6. Make the smallest maintainable change. Prefer a clear reusable class, a deliberate layer adjustment, or reduced specificity in the original rule over repeatedly appending ancestors or IDs. Use !important only when the priority is intentional and document it where maintainers will see it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How to avoid specificity problems in a stylesheet

Use classes for reusable component rules

Keep component selectors predictable rather than tying them to long ancestor chains. Extra nesting does not automatically make a stylesheet easier to maintain, and combinators add no specificity. A later override should not require reconstructing the component’s entire DOM path.

Use :where() for low-weight scoping

When a rule needs a scope for clarity but should be easy to override, place that scope inside :where(). This is especially helpful for defaults or styles intended to be customized by consumers.

Set layer order deliberately

Use cascade layers to express which category of normal styles should take precedence. This can resolve conflicts across a reset, vendor stylesheet, component styles, and application overrides without making each selector heavier. Remember the distinct normal and important layer ordering, and account for unlayered normal rules.

Do not escalate selectors reflexively

Adding ancestors, IDs, or !important can solve one immediate conflict while making future overrides more difficult. First identify which cascade stage caused the loss; then change that stage rather than inflating specificity by habit.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
CSS Pocket Reference
  • Ships from Vermont

Or skip the browser setup

If you need a clean visual capture of a rendered page while reproducing a CSS issue, ScreenshotNeo can return an image or PDF from one GET request. It does not inspect or explain CSS; use browser developer tools for the cascade diagnosis. Example request, using https://stripe.com as the target URL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for free.

Frequently Asked Questions

Does adding more parent elements always make a selector stronger?

No. Combinators and the relationships they describe add no specificity; only the selector components in the three columns count.

Can a selector with an ID lose to a selector with many classes?

Not on specificity alone: the ID column is compared first. It can still lose if an earlier cascade criterion, such as importance or layer precedence, decides the conflict.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quick Recap

Bestseller No. 2
Pocket Ref
Pocket Ref
Author: Thomas Glover; 864 pages; 3.2" x 5.4", softbound; (Also available in Desk Size item 2072)
$12.95
Bestseller No. 5
CSS Pocket Reference
CSS Pocket Reference
Ships from Vermont
$7.78

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.