
CSS Not Working? 7 Reasons Your Styles Are Not Applying
Skilldham
Engineering deep-dives for developers who want real understanding.
Every developer has faced this moment.
You write a CSS rule. You refresh the page. Nothing changes.
You double-check the code again. It looks perfectly correct. You even copy-paste the same CSS somewhere else - and suddenly it works there.
This is one of the most frustrating debugging experiences in frontend development. You are not doing anything wrong on the surface. The syntax is fine. The selector looks right. And yet the browser completely ignores what you wrote.
The truth is: when CSS is not working, the problem is almost never the code you just wrote. It is usually something else silently overriding it - a specificity conflict, a cascade issue, a missing file, or a layout context you did not account for.
Let's go through every reason, with real examples and exact fixes.
CSS Specificity Is Overriding Your Styles
Specificity is the number one reason CSS stops working - and it trips up even experienced developers.
CSS follows a priority system. When two rules target the same element, the browser does not just pick the one that appears last. It calculates a specificity score for each selector, and the one with the higher score wins - regardless of order.
The scoring works like this:
Inline styles → (1, 0, 0, 0) highest
ID selectors → (0, 1, 0, 0)
Class selectors → (0, 0, 1, 0)
Element selectors → (0, 0, 0, 1) lowestWrong - expecting the later rule to win:
css
/* You wrote this */
.button {
color: red;
}
/* Framework or another file has this */
.container .button {
color: blue;
}Even though .button might appear later in your file, .container .button wins because it has higher specificity - it targets both a parent and a child.
Correct - match or beat the specificity:
css
/* Option 1: Add the same parent context */
.container .button {
color: red;
}
/* Option 2: Add your own wrapper */
.hero .button {
color: red;
}The fastest way to debug this is Chrome DevTools. Open it, inspect the element, and look at the Styles panel on the right. Rules that are being overridden show up with a strikethrough line through them. The browser is literally telling you which rule lost and why.
If you want a deeper understanding of how the browser calculates specificity scores, the MDN documentation on CSS specificity walks through every edge case.

Another CSS Rule Is Loaded After Yours
If two selectors have the exact same specificity, the browser uses a simpler tiebreaker - whichever rule appears later in the stylesheet wins.
This is called the cascade, and it catches developers off guard constantly.
Wrong - two identical selectors, wrong order:
css
/* Your rule */
.button {
color: red;
}
/* Same selector somewhere else - this wins */
.button {
color: blue;
}The button will always be blue because the second rule appears later. This is not a bug - it is how CSS is designed to work.
Where this commonly breaks:
css
/* You import your styles first */
@import './my-styles.css';
/* Then a framework loads after - it overrides everything */
@import 'bootstrap/dist/css/bootstrap.min.css';Bootstrap or Tailwind's base styles loading after your custom styles will override them silently. The fix is to either load your styles after the framework, or increase your selector specificity so the framework cannot override them.
Correct - load your styles after the framework:
css
/* Framework first */
@import 'bootstrap/dist/css/bootstrap.min.css';
/* Your overrides after - these win now */
@import './my-styles.css';The Selector Does Not Match the Element
Sometimes the issue is simpler than anything else. The selector just does not match the element in your HTML.
This happens more often than anyone wants to admit.
Wrong - targeting id instead of class:
css
/* CSS targets an ID */
#button {
color: red;
}html
<!-- HTML uses a class, not an ID -->
<button class="button">Click me</button>The #button selector only matches elements with id="button". Since your element uses class="button", the rule does nothing.
Correct - match selector to actual HTML:
css
/* Use class selector to match class="button" */
.button {
color: red;
}Other common mismatches:
css
/* Wrong - extra space creates descendant selector */
.nav .button { } /* only matches .button inside .nav */
/* Wrong - targeting wrong element type */
div.card { } /* only matches <div class="card">, not <section class="card"> */Whenever CSS is not working and you cannot find a specificity issue, inspect the element in DevTools and manually check what class names and IDs are actually on it. Copy-paste from DevTools directly into your CSS - do not type it from memory.
Your CSS File Is Not Actually Loading
Another classic problem that wastes hours. Your stylesheet might not even be connected to the page.
When a browser cannot find a CSS file, it silently ignores the error. No warning, no broken page - just styles that do nothing. This is why it is so hard to catch.
Wrong - incorrect file path:
html
<!-- You wrote this -->
<link rel="stylesheet" href="/style.css">
```
```
But the file is actually at:
/css/style.css ← different folderCorrect - match the path exactly:
html
<link rel="stylesheet" href="/css/style.css">How to check: Open Chrome DevTools - Network tab - filter by CSS - reload the page. If you see a 404 status next to your CSS file, it is not loading. The URL shown in the Network tab is exactly what the browser is trying to request - use that to find the mismatch.
In Next.js specifically, CSS files inside the app or pages directory need to be imported in the right place. Global styles go in app/layout.js, not in individual components. If you are having CSS issues specifically in a Next.js project, check out our guide on Next.js Image Not Showing - the same principle of incorrect paths applies there too.
Flexbox or Grid Is Changing CSS Behavior
Sometimes your CSS is technically working - but the layout context you are in changes how properties behave. This is especially common with Flexbox and Grid, where several CSS properties work differently than they do in normal document flow.
Common example - margin: auto in Flexbox:
css
/* Normal flow - margin: auto pushes element down */
.element {
margin-top: auto;
}
/* Inside a flex container - margin: auto centers it! */
.flex-parent {
display: flex;
}
.element {
margin: auto; /* now centers horizontally AND vertically */
}Wrong - expecting width: 100% to work normally:
css
.flex-child {
width: 100%; /* behaves differently in flex context */
}Correct - use flex properties instead:
css
.flex-child {
flex: 1; /* takes available space properly */
}
```
Other properties that behave differently inside Flex or Grid containers: `align-self`, `justify-self`, `float` (completely ignored), `vertical-align` (ignored), and `display: inline` (overridden by flex/grid).
When your CSS is not working inside a layout component, always check the parent's display property first. The parent context completely changes how children behave.
---
## The Browser Is Caching Your Old CSS
You make a change. You save. You refresh. Nothing changes. But you are looking right at the updated file in your editor.
This is browser caching - and it is one of the most disorienting CSS problems because everything looks correct but the browser is still serving the old version.
**Quick fixes:**
```
Hard refresh:
Mac: Cmd + Shift + R
Windows: Ctrl + Shift + R
Disable cache while DevTools is open:
DevTools - Network tab - check "Disable cache"
(only disables while DevTools is open)Production fix - cache busting:
html
<!-- Add a version query string to force re-download -->
<link rel="stylesheet" href="/style.css?v=2">js
// In Next.js - this is handled automatically
// next build generates hashed filenames like:
// /_next/static/css/ba5a0ad9ebb80905.css
// Any CSS change = new filename = new downloadThis problem is especially frustrating during deployment. If your Vercel deployment looks wrong but the code is correct, try opening the site in an incognito window first. If it looks right in incognito, it is a caching issue on your browser, not a deployment problem. Check our guide on why your Next.js build fails on Vercel for more deployment-related CSS issues.
!important Is Breaking Your Styles
!important is the last resort of CSS - and it causes more problems than it solves.
When you add !important to a rule, it overrides everything else, including inline styles. The problem is when multiple rules use !important - then specificity fights start again, but now they are even harder to debug.
Wrong - using !important as a quick fix:
css
.button {
color: red !important;
}
/* Later, someone else adds this */
.button {
color: blue !important; /* now BOTH have !important */
}When two !important rules conflict, specificity kicks back in - and you have made the problem impossible to resolve cleanly.
Correct - fix the root cause instead:
css
/* Instead of !important, fix the specificity properly */
.hero-section .cta-button {
color: red; /* specific enough, no !important needed */
}
```
The only legitimate use of `!important` is utility classes - like Tailwind's `!text-red-500` - where overriding all other styles is the intentional purpose.
If you find yourself reaching for `!important`, treat it as a signal that your CSS architecture needs to be cleaned up, not patched.
---
## How to Debug CSS Problems Properly
When CSS is not working, open DevTools immediately - do not guess.
```
1. Right-click the element - Inspect
2. Styles panel on the right
3. Look for crossed-out rules - those are being overridden
4. Check which rule is winning
5. Check the selector of the winning rule
6. Either match that specificity or restructure your CSSDevTools also has a Computed tab that shows you the final resolved value of every CSS property on an element. This is especially useful when you cannot find where a value is coming from.
Key Takeaway
When CSS is not working, work through this checklist:
Open DevTools and look for crossed-out rules - specificity conflict is the most common cause
Check cascade order - the same-specificity rule that loads last wins
Verify your selector exactly matches the element - id vs class is a frequent mistake
Check the Network tab to confirm your CSS file is actually loading with a 200 status
Consider the layout context - Flex and Grid change how many properties behave
Hard refresh with Ctrl+Shift+R or disable cache in DevTools to rule out caching
Avoid !important - it signals a deeper structural problem
Once you understand how the browser actually applies styles - specificity, cascade, inheritance - CSS debugging stops being frustrating and becomes a straightforward investigation.
FAQs
Why is my CSS not working even though the code looks correct? The most common reason is a specificity conflict - another rule targeting the same element has a higher specificity score and is silently overriding yours. Open Chrome DevTools and look for crossed-out rules in the Styles panel to find the exact conflict.
How do I check which CSS rule is actually being applied? Open Chrome DevTools with F12 - right-click the element - Inspect - look at the Styles panel on the right. Rules with strikethrough text are being overridden. The active rule is shown at the top of the cascade.
Can browser caching prevent CSS changes from showing up? Yes, this is very common - especially after deployment. Do a hard refresh with Ctrl+Shift+R on Windows or Cmd+Shift+R on Mac. If the site looks correct in incognito mode but not in your normal browser, it is definitely a caching issue.
Why does CSS work in one place but not another? Usually this means the selector is correct but the element is inside a different layout context - Flexbox or Grid changes how properties like margin, width, and alignment behave. Check the parent element's display property first.
What is the difference between specificity and cascade in CSS? Specificity determines which rule wins when two different selectors target the same element - the one with the higher score wins regardless of order. Cascade is the tiebreaker when two rules have identical specificity - the one that appears later in the stylesheet wins.
When should I use !important in CSS? Almost never in application code. The only legitimate use is in utility-class systems like Tailwind where overriding all other styles is intentional. In normal CSS, if you need !important, it usually means there is a specificity problem that needs to be fixed at the root.