Beginner30 minutesCSSTroubleshooting

Why Your CSS Isn’t Working (And How to Fix It)

Learning Objectives

By the end of this lesson, you'll be able to:

  • Identify Identify the most common reasons CSS rules are ignored by the browser
  • Diagnose CSS syntax errors including missing brackets, colons, and semicolons
  • Explain Explain how specificity and the cascade determine which styles win
  • Use browser DevTools to inspect, toggle, and edit CSS rules in real time
  • Apply Apply a systematic debugging checklist to fix broken styles quickly

Why This Matters:

Professional developers spend a surprising amount of time debugging CSS. The difference between a beginner and an expert isn’t that experts never have CSS problems — it’s that they can find and fix them in seconds. This tutorial gives you the same mental checklist that experienced developers use, so you stop guessing and start diagnosing.

Is Your CSS Even Loading?

Before you blame your rules, make sure the browser is actually reading your stylesheet. This is the number one cause of “my CSS isn’t working” for beginners — and it’s the easiest to fix.

Check 1: Is the <link> tag in your HTML?

Your HTML file needs a <link> element in the <head> that points to your stylesheet:

<head>
    <meta charset="UTF-8">
    <title>My Page</title>
    <link rel="stylesheet" href="css/style.css">
</head>

If this line is missing, your CSS file exists but the browser has no idea it’s there. It’s like writing a letter and never posting it.

Check 2: Is the file path correct?

The href must match the actual location of your CSS file. If your stylesheet is in a css/ folder, the path needs to include that folder:

Correct

<!-- File is at css/style.css -->
<link rel="stylesheet"
      href="css/style.css">

<!-- File is in the same folder -->
<link rel="stylesheet"
      href="style.css">

Wrong

<!-- File is at css/style.css
     but path says root -->
<link rel="stylesheet"
      href="style.css">

<!-- Typo in folder name -->
<link rel="stylesheet"
      href="CSS/styles.css">

Case matters on servers

style.css and Style.css are the same file on your Mac — but on a Linux web server, they’re two different files. Always use lowercase filenames.

Check 3: Browser cache

Browsers cache (save a copy of) your CSS to load pages faster. When you edit your stylesheet and refresh, you might be seeing the old cached version.

Fix: Do a hard refresh:

  • Mac: Cmd + Shift + R
  • Windows/Linux: Ctrl + Shift + R

Or open DevTools (F12), go to the Network tab, and tick “Disable cache” while DevTools is open.

Think of caching like a photocopy:

The browser takes a photocopy of your stylesheet and uses that instead of checking the original file every time. A hard refresh forces it to throw away the photocopy and look at the real file again.

Syntax Errors: The Silent Breakers

CSS doesn’t throw error messages like JavaScript. If you make a syntax mistake, the browser silently skips the broken rule — and sometimes everything that comes after it.

Missing curly brackets

If you forget a closing }, the browser can’t tell where your rule ends. Every rule below the missing bracket may also break.

Correct

h1 {
    color: navy;
    font-size: 2rem;
}

p {
    line-height: 1.6;
}

Broken

h1 {
    color: navy;
    font-size: 2rem;

/* Missing } above!
   The p rule gets swallowed */
p {
    line-height: 1.6;
}

Missing colons and semicolons

Every CSS declaration needs a colon between the property and value, and a semicolon at the end:

/* ✅ Correct */
color: navy;
font-size: 2rem;

/* ❌ Missing colon */
color navy;

/* ❌ Missing semicolon */
color: navy
font-size: 2rem

A missing semicolon can cause the next property to be treated as part of the current value — the browser sees color: navy font-size: 2rem as one invalid value and ignores both.

Space between value and unit

This one catches people all the time:

/* ✅ Works */
font-size: 26px;
margin: 1.5rem;

/* ❌ Broken — space between number and unit */
font-size: 26 px;
margin: 1.5 rem;

CSS requires the number and unit to be one continuous token. A space between them makes the value invalid, and the rule is silently ignored.

Why doesn’t CSS show error messages?

CSS was designed to be forward-compatible. When browsers encounter a property or value they don’t understand, they skip it instead of crashing. This means new CSS features can be added without breaking old browsers — but it also means your typos get silently ignored instead of flagged.

⏸️ ⏸️ Check: Loading & Syntax

Can you spot the problems?

  1. Your page has no styles at all. What is the very first thing you should check?
  2. You edited your CSS but the page still looks the same after refreshing. What could cause this?
  3. What happens when you forget a closing curly bracket } in CSS?
Check Your Answers
  1. Check that the <link> tag is in the <head> of your HTML and that the href path is correct. If the stylesheet isn’t linked, the browser has no idea it exists.
  2. Browser caching. The browser is showing you the old saved version of your stylesheet. Do a hard refresh (Cmd+Shift+R on Mac, Ctrl+Shift+R on Windows/Linux) to force it to re-download the file.
  3. The browser can’t tell where the rule ends, so it swallows everything that follows until it finds another closing bracket. This can break multiple rules below the mistake, not just the one with the error.

How confident are you with this concept?

😕 Still confused | 🤔 Getting there | 😊 Got it! | 🎉 Could explain it to a friend!

Selector Issues: Targeting the Wrong Thing

Your CSS might be perfectly valid, but if the selector doesn’t match any element in your HTML, the rule has nothing to style.

Typos in class and ID names

This is embarrassingly common — and hard to spot because CSS gives you no warning:

<!-- HTML -->
<div class="hero-banner">...</div>

/* CSS — typo! "heros" instead of "hero" */
.heros-banner {
    background: navy;
}

The selector .heros-banner matches nothing, so the rule is silently ignored. Always copy-paste class names from your HTML into your CSS to avoid this.

Forgetting the dot or hash

/* ❌ Targets an element called <hero-banner>
   (which doesn't exist) */
hero-banner {
    background: navy;
}

/* ✅ Targets class="hero-banner" */
.hero-banner {
    background: navy;
}

/* ✅ Targets id="hero-banner" */
#hero-banner {
    background: navy;
}

Invalid selector lists

If you group selectors with commas and one of them is invalid, the entire rule is ignored in standard CSS:

/* ❌ :invalid-pseudo doesn't exist
   — the ENTIRE rule is thrown out */
h1, h2, :invalid-pseudo {
    color: navy;
}

/* ✅ Split them so a bad selector
   doesn't break the good ones */
h1, h2 {
    color: navy;
}

Copy-paste is your friend

Instead of retyping class names, copy the class name from your HTML and paste it into your CSS. This eliminates typo-based selector mismatches instantly.

Specificity & the Cascade

This is where beginners get stuck the most. You write a rule, the selector is correct, the syntax is perfect — but the browser is applying a different rule instead. Why?

The cascade: last rule wins

When two rules have the same specificity and target the same element, the one that appears later in the stylesheet wins:

h1 {
    color: red;
}

/* This one wins — it comes later */
h1 {
    color: blue;
}

Specificity: more specific rules win

But when rules have different specificity, the more specific one wins regardless of order. Think of specificity as a scoring system:

Specificity scoring (simplified)
Selector TypeScoreExample
Element1 pointp, h1, div
Class10 points.hero, .nav-link
ID100 points#header, #main
Inline style1000 pointsstyle="color: red"
/* Specificity: 1 (one element) */
p {
    color: black;
}

/* Specificity: 10 (one class) — WINS */
.intro {
    color: navy;
}

/* Specificity: 11 (one element + one class) */
p.intro {
    color: red;
}

A class selector (.intro) always beats a plain element selector (p), no matter which comes first in the file.

Think of specificity like an address:

“Deliver this to any house on the street” (element selector) is vague. “Deliver to the blue house” (class) is more specific. “Deliver to 42 Smith Street” (ID) is exact. The more specific instruction always wins.

The !important trap

You might see advice to add !important to force a rule to win:

p {
    color: red !important;
}

This works — but it’s a trap. Once you start using !important, the only way to override that rule is with another !important, and soon your stylesheet becomes an unmanageable mess. Professional developers treat !important as a last resort, not a first fix.

Instead of !important:

  1. Make your selector more specific (add a class or parent selector)
  2. Move the rule later in the stylesheet
  3. Remove the conflicting rule that’s winning

⏸️ ⏸️ Check: Selectors & Specificity

Test your understanding:

  1. You wrote .hero { color: red; } but the text stays black. In DevTools, you see that p { color: black; } has a line through it and body { color: black; } does not. What’s happening?
  2. Which selector wins: p { color: red; } or .intro { color: blue; }?
  3. Why is !important considered bad practice?
Check Your Answers
  1. The colour is being inherited from body, not from a p rule. Since .hero doesn’t have a colour conflict with a higher-specificity rule, check that the selector actually matches — the class name might be misspelled in the HTML or CSS.
  2. .intro wins because a class selector (specificity ~10) always beats an element selector (specificity ~1), regardless of which comes first in the stylesheet.
  3. Because the only way to override an !important rule is with another !important rule that has equal or higher specificity. This creates an escalating war of !important declarations that makes your stylesheet very difficult to maintain.

How confident are you with this concept?

😕 Still confused | 🤔 Getting there | 😊 Got it! | 🎉 Could explain it to a friend!

Inheritance & Third-Party Conflicts

Some CSS properties are inherited — child elements automatically pick up the value from their parent. Others are not.

What inherits and what doesn’t

Inherited

  • color
  • font-family
  • font-size
  • line-height
  • text-align

Set these on a parent and children get them for free.

NOT inherited

  • background
  • border
  • margin
  • padding
  • width / height

You must set these on each element individually.

Third-party CSS conflicts

If you’re using a CSS framework (Bootstrap, Bulma, Tailwind) or a CMS theme, their styles load alongside yours. When your rules don’t seem to take effect, the framework’s rules are probably winning the specificity battle.

/* Bulma's button styles might be:
   .button { background-color: white; }
   Specificity: 10

   Your override needs at least the same specificity: */
.button.my-custom-button {
    background-color: navy;
}
/* Specificity: 20 — wins! */

Tip: In DevTools, look for rules with a line-through — that means they’re being overridden by a more specific rule. The winning rule is shown above it.

Browser DevTools: Your CSS Debugger

DevTools is the single most valuable tool for debugging CSS. Every browser has them built in — no installation required.

Opening DevTools

  • All browsers: Press F12 or right-click any element → Inspect
  • Mac shortcut: Cmd + Option + I
  • Windows/Linux: Ctrl + Shift + I

The Elements panel

The Elements panel shows your HTML on the left and the CSS rules for the selected element on the right. This is where you’ll do most of your debugging.

Key debugging techniques

  1. Inspect the element — Right-click the problem element → Inspect. The Styles panel shows every CSS rule that applies.
  2. Look for crossed-out rules — A line through a property means it’s being overridden by another rule. Look above it to see what’s winning.
  3. Toggle rules on/off — Click the checkbox next to any property to disable it temporarily. This is the fastest way to find which rule is causing a problem.
  4. Edit values live — Click on any value (e.g. navy) and type a new one. The page updates instantly. This lets you experiment without touching your file.
  5. Check the Computed tab — This shows the final value the browser is actually using, after all cascade and inheritance calculations.
DevTools is like an X-ray for your page:

It lets you see inside the page — which rules are applied, which are overridden, and exactly why. If CSS is the clothes your page wears, DevTools lets you see the skeleton underneath.

The outline trick for layout debugging

If an element seems to be the wrong size or in the wrong place, try adding a temporary outline to everything:

/* Add this temporarily */
* {
    outline: 1px solid red;
}

This draws a red border around every element so you can see their boundaries. Unlike border, outline doesn’t affect the element’s size or layout, so it won’t change what you’re debugging.

⏸️ ⏸️ Check: DevTools

Make sure you know the essentials:

  1. How do you open DevTools in any browser?
  2. In the Styles panel, what does a line through a CSS property mean?
  3. Why is outline better than border for debugging layout issues?
Check Your Answers
  1. Press F12, or right-click any element and choose Inspect. On Mac you can also use Cmd+Option+I.
  2. It means that property is being overridden by another rule with higher specificity or that appears later in the cascade. The winning rule is shown above the crossed-out one.
  3. Unlike border, outline does not affect the element’s size or layout. Adding a border changes the element’s dimensions (unless you use box-sizing: border-box), which can shift the layout and change the very problem you’re trying to debug.

How confident are you with this concept?

😕 Still confused | 🤔 Getting there | 😊 Got it! | 🎉 Could explain it to a friend!

Layout Gotchas

Some CSS problems aren’t about individual properties — they’re about how elements interact with each other in the layout.

Overflow issues

If content is spilling outside its container or a horizontal scrollbar appears, check for:

  • Fixed-width elements inside a flexible container
  • Images wider than their parent (fix: img { max-width: 100%; })
  • Padding or borders adding to the element’s total width (fix: box-sizing: border-box)

Collapsed margins

When two vertical margins touch, they don’t add up — the larger one wins. This is called margin collapsing and it catches everyone off guard:

/* You'd expect 40px of space between them.
   You actually get 30px (the larger margin wins). */
h1 {
    margin-bottom: 20px;
}
p {
    margin-top: 30px;
}

Z-index confusion

z-index only works on elements with a position value other than static. This is the most common reason z-index “doesn’t work”:

/* ❌ Won't work — no position set */
.popup {
    z-index: 999;
}

/* ✅ Works — position is set */
.popup {
    position: relative;
    z-index: 999;
}

Your CSS Debugging Checklist

When your CSS isn’t working, run through this checklist in order. Most problems are found in the first three steps:

The Checklist

  1. Is the stylesheet linked? — Check the <link> tag in your HTML <head>
  2. Is the file path correct? — Check for typos and wrong folder paths
  3. Is it cached? — Do a hard refresh (Cmd/Ctrl + Shift + R)
  4. Any syntax errors? — Check for missing {}, :, and ;
  5. Does the selector match? — Check class/ID spelling, dots, and hashes
  6. Is it being overridden? — Open DevTools and look for crossed-out rules
  7. Is specificity losing? — Make your selector more specific
  8. Is it inherited or not? — Check whether the property inherits
  9. Browser compatibility? — Check MDN for browser support

Guided Practice: Fix These Broken Styles

Download the starter files:

Save both files to a folder on your computer (keep the css/ subfolder structure).

Debug a Broken Stylesheet

You’ve been given a webpage with CSS that isn’t working. Use your debugging checklist to find and fix each issue.

Create the test page

Create a new file called debug-practice.html and add this HTML:




    
    CSS Debug Practice
    


    

My Website

Welcome

This is a test page for debugging CSS.

💡 Need a hint?
Make sure you create a css/ folder and put the stylesheet inside it.

Create the broken stylesheet

Create css/debug.css with these intentionally broken rules:

/* Bug 1: Missing closing bracket */
h1 {
    color: navy;
    font-size: 2.5rem;

/* Bug 2: Selector typo */
.hero_section {
    background-color: #f0f0f0;
    padding: 3rem;
}

/* Bug 3: Missing colon */
nav ul {
    list-style none;
    display: flex;
    gap: 1.5rem;
}

/* Bug 4: Space in value */
.intro {
    font-size: 1.2 rem;
    line-height: 1.8;
}
💡 Need a hint?
There are 4 bugs. Can you spot them just by reading the code before opening the browser?

Open the page and observe

Open debug-practice.html in your browser. Notice what looks wrong:

  • Is the h1 styled?
  • Does the hero section have a background?
  • Is the nav list horizontal?
  • Is the intro paragraph larger?

Open DevTools (F12) and inspect the h1 element. What do you see in the Styles panel?

💡 Need a hint?
If the h1 has no styles at all, the bug might be breaking not just its own rule but everything below it too.

Fix Bug 1: Missing bracket

Add the missing } after the h1 rule. Save and hard-refresh. The h1 should now be navy and large — and the rules below it should start working.

h1 {
    color: navy;
    font-size: 2.5rem;
}  /* ← This was missing! */
💡 Need a hint?
A missing closing bracket can break every rule that comes after it. Always fix bracket issues first.

Fix Bugs 2–4

Now fix the remaining three bugs:

  1. Bug 2: The HTML uses class="hero-section" but the CSS says .hero_section (underscore vs hyphen). Change the CSS to .hero-section
  2. Bug 3: list-style none is missing a colon. It should be list-style: none;
  3. Bug 4: 1.2 rem has a space. Remove it to get 1.2rem
💡 Need a hint?
After each fix, save and refresh to confirm it worked. Fix one bug at a time so you know which fix solved which problem.

Verify in DevTools

After all fixes, inspect each element and confirm:

  • h1 — Styles panel shows color: navy and font-size: 2.5rem (no line-through)
  • .hero-section — Shows background-color: #f0f0f0
  • nav ul — Shows display: flex and list-style: none
  • .intro — Shows font-size: 1.2rem

No rules should be crossed out or inactive.

💡 Need a hint?
If any rule still has a line through it, another rule is overriding it. Check specificity.

You're on track if you can:

  • ☐ All headings are styled with the correct colours
  • ☐ The navigation links appear horizontally
  • ☐ The hero section has its background colour
  • ☐ No CSS rules are being silently ignored
  • ☐ You can explain why each fix works

Independent Challenge: CSS Detective

Download the challenge files:

This page has 7 bugs hidden in the CSS. Save both files and use DevTools to find and fix them all.

💪 CSS Detective: Find All the Bugs

Now try this on your own without hints!

Your Task:

You’ve been hired to fix a client’s website. Their stylesheet has 7 different CSS problems — a mix of loading issues, syntax errors, selector problems, and specificity conflicts. Create a simple HTML page with an intentionally broken stylesheet, then systematically find and fix each bug using DevTools and the debugging checklist.
Requirements:
  • Create an HTML page with at least a header, nav, hero section, and footer
  • Write a CSS file with at least 7 intentional bugs (mix of categories from this tutorial)
  • Include at least one missing-bracket error that breaks rules below it
  • Include at least one selector typo (class name mismatch)
  • Include at least one specificity conflict where the wrong rule wins
  • Use DevTools to identify each bug before fixing it
  • Document each bug you planted and how you fixed it in an HTML comment
Stretch Goals (Optional):
  • Add a third-party CSS file (like a simple reset) and create a conflict that your custom styles need to override
  • Use the browser Computed tab to trace an inherited property through three levels of nesting
  • Create a z-index bug and fix it by adding the correct position property

Success Criteria:

CriteriaYou've succeeded if...
7+ intentional bugs covering at least 3 categoriesMeets expectations
Each bug is documented with the fix in a commentMeets expectations
DevTools was used (not just guessing) to diagnoseMeets expectations
Stretch goals attempted — third-party conflict or z-index fixExceeds expectations
Clean, well-organised final stylesheet after all fixesExceeds expectations

Summary

🏁 Lesson Complete: You Can Debug CSS

Key Takeaways:

  • Always check the basics first: is the stylesheet linked, is the path correct, is the browser cached?
  • CSS fails silently — a missing bracket, colon, or semicolon can break rules with no error message
  • Specificity determines which rule wins: IDs beat classes, classes beat elements, and !important overrides all (but use it as a last resort)
  • Browser DevTools let you inspect, toggle, and edit CSS rules in real time — learn to use them
  • Most CSS problems fall into just a few categories: run through the debugging checklist and you’ll find the issue quickly

Learning Objectives Review:

Look back at what you set out to learn. Can you now:

  • ✅ Identify the most common reasons CSS rules are ignored by the browser Check!
  • ✅ Diagnose CSS syntax errors including missing brackets, colons, and semicolons Got it!
  • ✅ Explain how specificity and the cascade determine which styles win Can explain it!
  • ✅ Use browser DevTools to inspect, toggle, and edit CSS rules in real time Could teach this!
  • ✅ Apply a systematic debugging checklist to fix broken styles quickly Check!

If you can confidently answer "yes" to most of these, you're ready to move on!

Think & Reflect:

💭 💭 Reflection Questions

  • Which type of CSS bug have you encountered most often in your own projects?
  • How will using DevTools change the way you debug styles compared to just editing the file and refreshing?
  • Why do you think CSS was designed to fail silently instead of showing error messages?
  • What is the first thing you will check next time your CSS doesn’t work?

🤔 Real-World Test:

Professional developers debug CSS every single day. The difference between a beginner and an expert isn’t that experts write perfect CSS — it’s that they can identify and fix problems in seconds using a systematic approach:

  1. Check the obvious (is the file loading?)
  2. Use DevTools to see what the browser is actually doing
  3. Fix one thing at a time and test after each change

Print out the debugging checklist from this tutorial and keep it next to your computer until it becomes second nature.

🎯 Looking Ahead:

Now that you can debug CSS, you’re ready to start writing more ambitious stylesheets. In the CSS Flexbox tutorial, you’ll learn modern layout techniques — and you’ll have the debugging skills to fix any problems along the way.

Recommended Next Steps

Practice Projects

Apply what you've learned with these hands-on projects:

CSS Debug Practice

A broken stylesheet with 4 bugs to find and fix using DevTools.

CSSDebugging
Start Project

Additional Resources

Deepen your understanding with these helpful resources:

Progress tracking is disabled. Enable it in to track your completed tutorials.