Table of contents8
A client once sent me a screenshot of his website with one angry sentence: “The button is still blue. I changed it to green three hours ago.” I opened his site, opened his Additional CSS panel, and saw a perfectly correct rule: .button { background: green; }. The CSS was fine. The button stayed blue anyway. I spent the next hour doing what every frustrated WordPress user does — adding !important, making the selector longer, refreshing like a maniac — before I finally learned the real lesson. His CSS was never broken. It was losing a fight it didn’t know it was in. This CSS specificity WordPress guide is the explanation I wish someone had given me that afternoon.
I am Lukas Weber, and I have been building and fixing WordPress front ends for eight years. Specificity is the single most misunderstood concept I encounter, and it is the reason behind most “my CSS doesn’t work” complaints I have ever investigated. Once you understand it, you stop fighting your theme and start winning cleanly — usually without !important at all.
Here is my promise: by the end of this article, you will understand the exact scoring system browsers use to decide which CSS rule wins, you will know how to diagnose any losing rule in sixty seconds with browser dev tools, and you will have three reliable techniques for writing selectors that beat your theme’s styles without resorting to !important. If you have ever pasted CSS into WordPress, refreshed, and felt personally betrayed by a button that refused to change color, this is for you. Let’s fix it properly.

One reassurance first: nothing is wrong with your CSS knowledge. Specificity is genuinely confusing because it is invisible — two rules can look equally valid while the browser quietly picks a winner using math you were never shown. This is not a beginner problem. I have watched professional developers lose entire afternoons to it.
Here is what this guide to CSS specificity in WordPress covers:
- Understand the specificity scoring system browsers actually use
- See why your theme’s styles beat yours, with real WordPress examples
- Diagnose any losing rule in sixty seconds with dev tools
- Write selectors that win cleanly, without !important
- Know the rare cases where !important is honestly fine
- Avoid the mistakes that start specificity wars
- Frequently asked questions
- Final thoughts
Ready? Let’s get started.
Your CSS Isn’t Broken — It’s Losing a Fair Fight
Here is the mental shift that changed everything for me. When your CSS “doesn’t work,” the browser is not ignoring you. It is following a rule — a scoring system — and your rule simply scored lower than someone else’s. CSS stands for Cascading Style Sheets, and the “cascade” is literally the process of resolving conflicts between competing rules. Your theme ships with hundreds of rules. Your custom CSS adds a few more. When two rules target the same element and set the same property, the browser doesn’t panic or pick randomly. It calculates a score for each selector, and the higher score wins. Every time. Predictably.
Think of it like a card game where every selector is a hand. An element selector like h1 is a low card. A class like .entry-title beats any number of element selectors. An ID like #main-title beats any number of classes. Once I started seeing selectors as scores instead of instructions, the mystery evaporated. Your rule didn’t fail. It just brought a knife to a gunfight, and now I’m going to teach you to count the weapons before you fight.
CSS Specificity WordPress: How the Scoring System Works
The scoring system is simpler than it looks. Every selector gets a three-part score — think of it as three columns: IDs, classes, elements. Count the IDs in your selector for the first column, the classes (plus attributes and pseudo-classes like :hover) for the second, and the element names (plus pseudo-elements) for the third. Compare column by column, left to right. The first column where the scores differ decides the winner. So #header .nav a scores 1-1-1, and it beats .header .nav .link at 0-3-0, because the ID column decides it before classes even matter.
Now watch how this plays out in a real WordPress theme. Your theme’s stylesheet contains something like this:
/* Your theme's CSS (score: 0-2-0) */
.site-content .entry-title {
color: #1a1a1a;
}
And you add this in the Customizer’s Additional CSS panel:
/* Your CSS (score: 0-1-0) — loses */
.entry-title {
color: #b91c1c;
}
Your rule is perfectly valid CSS. It targets the right element. It just scores 0-1-0 against the theme’s 0-2-0, so the theme wins and your title stays dark. That is the heart of CSS specificity WordPress themes are built on: themes write long, specific selectors, and your short selector can’t outscore them. Notice what also matters here: because your Additional CSS loads after the theme stylesheet, you would win any tie. Order only breaks ties — it never beats a higher score. That is the detail most tutorials skip, and it is the one that makes everything click.
Bonus Tip: inline styles — the style="..." attribute written directly on an HTML element — beat everything except !important. Page builders and some plugins love inline styles, which is why their output can feel impossible to override. Keep that in your back pocket; it explains a whole category of mysteries, and I’ll show you the honest fix later.
Diagnose Any Losing Rule in 60 Seconds With Dev Tools
Before you change a single line of CSS, do what I do on every single case: open the losing element in your browser’s dev tools. Right-click the stubborn button, heading, or link, choose Inspect, and look at the Styles panel. This panel shows you every rule targeting that element, in winning order — and the losers are shown with a strikethrough. Your rule will be sitting there, crossed out, with the winner sitting above it, uncrossed. In sixty seconds you can see exactly which selector is beating you and what its score is.
This changed my debugging life. Instead of guessing — “maybe the cache, maybe a typo, maybe I need !important” — I read the actual evidence. The Styles panel tells you the winning selector verbatim, which means you can copy it and build your override directly from it. See that the winner is .site-content .entry-title? Then you know you need at least 0-2-0 to beat it fairly. No more guessing, no more refreshing like a maniac. The struck-through rule is the whole diagnosis. If your rule doesn’t appear in the panel at all, that’s a different problem — a typo in the selector, a syntax error earlier in your CSS, or caching — and knowing which problem you have saves you from fixing the wrong one.
While you’re in dev tools, try this: click into the Styles panel and edit the values live. Change the color, toggle the rule off and on, add a new declaration. Nothing you do here affects your real site — it’s a sandbox. I experiment in the browser until the element looks exactly right, then copy the winning CSS into WordPress. It’s the fastest feedback loop in all of web development, and it’s free. If you’re new to this workflow, my guide to copy-paste WordPress CSS recipes was written to pair with exactly this technique.
CSS Specificity WordPress: Write Selectors That Win Without !important
Now the fun part. You know the winner’s score, so you just need a selector that outscores it. Here are the three techniques I actually use, from cleanest to cleverest. Every one of them beats !important for maintainability, because future-you (or the next developer) can still override your rule normally instead of fighting a nuclear option.

Technique 1: Borrow the theme’s own selector and add one parent. This is my default. Take the winning selector you found in dev tools and prefix it with one more parent class — body always works, since every page has one:
/* Theme wins with 0-2-0, so beat it with 0-3-0 */
body .site-content .entry-title {
color: #b91c1c;
}
Clean, readable, and it documents itself: anyone reading it understands you’re deliberately overriding the theme. Technique 2: repeat the class. This one feels like cheating the first time you see it. Writing .button.button targets the same elements as .button, but it scores 0-2-0 instead of 0-1-0 — you doubled the class column without changing what the selector matches:
/* Same elements as .button, but scores 0-2-0 */
.button.button {
background: #16a34a;
}
I use this when the theme’s selector is already long and I don’t want to make mine longer. Add a short CSS comment explaining why the class is doubled, or some well-meaning person will “clean it up” later and break your site. Technique 3: match the winner exactly, then rely on order. If you copy the theme’s selector character for character, the scores tie — and your Additional CSS loads later, so you win the tie. This is the most surgical option, but it’s also the most fragile: if the theme updates and changes its selector, your tie becomes a loss. I only use it for quick, temporary fixes.
Notice what all three have in common: none of them escalate the arms race. Each one wins by exactly enough, which leaves room for the next override to win normally too. That discipline is what separates CSS that survives for years from CSS that collapses into a pile of !important declarations six months later. Speaking of which — let’s talk honestly about the nuclear option.
When !important Is Actually OK (The Honest Last Resort)
I am not going to tell you to never use !important. That advice is unrealistic, and it made me feel guilty for years about something that is sometimes simply the right tool. !important on a declaration beats everything except another !important with higher specificity. There are exactly three situations where I reach for it without apology.
One: overriding inline styles you don’t control. When a plugin or page builder writes style="width: 600px" directly on an element, no stylesheet selector can beat it — inline styles outscore all of them. Only !important wins that fight, and it’s the correct weapon for it. Two: global safety rules. A reduced-motion override for users who prefer it should beat every animation on the page, including ones from libraries you didn’t write. Three: utility classes. If you maintain a small set of helper classes like .hidden or .text-center, giving them !important guarantees they do what their name promises no matter where they’re used.

The rule for all three cases: use it on one property, and leave a comment saying why. /* beats plugin inline style */ takes five seconds to write and saves the next person an hour of confusion. What you must never do is use !important because you didn’t check the score. Every lazy !important forces the next override to use !important too, and that is how stylesheets turn into the specificity wars the Hostinger tutorials warn about — a pile of nuclear declarations where nobody remembers what beats what. Diagnose first, escalate last.
Mistakes That Start Specificity Wars
I have inherited enough client stylesheets to recognize the four habits that create unmaintainable CSS. Learn them here so you never have to unlearn them later. Mistake one: IDs in selectors. An ID scores 1-0-0 — it beats any number of classes — which feels powerful until you need to override it and discover nothing short of another ID or !important can. Style with classes; leave IDs for JavaScript hooks.
Mistake two: selector chains five levels deep. Something like body .site .content .post .entry p wins today and becomes un-overridable tomorrow. Long chains are also slow to read and brittle — one theme update renames a wrapper and the whole chain dies. Mistake three: pasting selectors from forums without understanding them. I did this for my first two years. The selector worked, I moved on, and six months later I had no idea why changing one rule broke three pages. If you can’t explain what each part of your selector matches, simplify it until you can.

Mistake four: treating caching as a specificity problem. If your new CSS doesn’t appear at all — not even crossed out in dev tools — that’s not specificity, that’s caching or a syntax error. Clear your browser cache and any caching plugin first; a surprising share of “specificity” mysteries are just stale files. This is also why keeping your site fast and your cache configured matters — the WordPress speed checklist covers cache setup properly. And if you want the broader safety mindset behind all of this, read how to customize WordPress without breaking it before your next round of tweaks.
Frequently Asked Questions
Why does my CSS work in the Customizer preview but not on the live site?
Almost always caching. The preview bypasses your cache, but visitors (and your logged-out self) get the cached old stylesheet. Clear your caching plugin and CDN cache after publishing CSS changes, then hard-refresh. If the rule shows as crossed-out in dev tools on the live site, it’s specificity, not cache — read the winner and outscore it.
If two rules have equal specificity, which one wins?
The one that comes later in the cascade. This is why CSS in the Customizer’s Additional CSS panel beats identical selectors in your theme’s stylesheet — it loads after them. Ties are broken by order; only unequal scores are decided by specificity.
Should I ever use IDs in my CSS selectors?
Almost never. An ID’s 1-0-0 score beats any number of classes, which makes it nearly impossible to override cleanly later. Use classes for styling and reserve IDs for JavaScript. If your theme uses IDs in its selectors, beat them with a parent class plus the same ID, or with a carefully justified !important.
What’s the difference between specificity and !important?
Specificity is the normal scoring system every selector participates in. !important is a separate override that beats the entire scoring system — a declaration with !important wins regardless of selector scores. Think of specificity as the league table and !important as the referee’s whistle: it ends the game, so use it sparingly.
Why does my plugin’s CSS beat my theme’s CSS?
Either the plugin’s selectors score higher, its stylesheet loads later, or it uses inline styles (which beat all selectors). Inspect the element, find the winning rule in dev tools, and you’ll see which one. Plugin inline styles are the most common cause — and that’s one of the honest use cases for !important.
Final Thoughts
That client’s green button? I fixed it in the end with body .site-content .button — one parent class, no !important, and it has survived three theme updates since. The hour I wasted before that taught me the lesson this whole guide is built on: CSS doesn’t have moods. It has math. And once you can do the math, the fear goes away.
You now know something most WordPress users never learn: the 1-0-0 scoring system, the sixty-second dev-tools diagnosis, and three clean techniques for winning without the nuclear option. The next time a style refuses to apply, you won’t refresh like a maniac. You’ll inspect, read the score, and outscore it. That is a genuinely professional skill, and you earned it in one article.
Honest line: I still lose to specificity sometimes — usually when a plugin update introduces some monstrous selector I didn’t expect. The difference is that now I know exactly where to look, and the mystery lasts minutes instead of hours. That is CSS specificity WordPress mastery: not never losing, but never being lost.
What is the most stubborn style you’ve ever fought — the one that made you question your career choices? Tell me in the comments. I read every one, and the best war stories might earn their own troubleshooting guide.










