Sometimes the task looks extremely simple: change a margin, padding, or another style.
I change the SCSS, refresh the page, and nothing happens.
The first reaction can be: "the CSS is not working". In practice, however, the actual problem is often somewhere else in the chain.
I recently ran into this again. Instead of continuing to change values at random, I traced the change step by step to find exactly where it disappeared.
First I Check Whether I Changed the Right File
In a large or older project, a single page may have several different style sources at the same time.
- legacy CSS;
- newer SCSS;
- page-specific styles;
- component styles;
- compiled CSS under
public; - overrides from another file.
So my first question is not "why does this margin not work?" but "does the file I am editing actually participate in this page?"
rg -n "my-selector" resources public # Real example:rg -n "lot-removed" resources publicgit diff -- path/to/file.scssIf the selector appears in multiple files, that alone is a reason to verify which source actually reaches the page.
git diff is also useful here, not only before a commit. It quickly confirms that I changed the exact block and value I intended to change.
Then I Check Whether the SCSS Was Actually Built
Changing a .scss file does not automatically mean the browser will see the change.
The browser does not read my source SCSS directly. It receives compiled CSS.
So the next question is: did my change actually pass through the frontend build?
cat package.json # Or only the scripts section:cat package.json | grep -A 20 '"scripts"'npm run dev # Or, depending on the project:npm run buildIn older projects, I do not assume that the command must be npm run dev or npm run build. I inspect package.json first.
The project may use a different build setup, multiple entry points, or separate commands for different parts of the frontend.
I Check Whether the Rule Reached the Compiled CSS
git status --short rg -n "my-selector" publicThis step separates a source problem from a build problem very quickly.
If the new rule exists in SCSS but cannot be found in the compiled assets, there is no reason to investigate specificity or browser cache yet. The change has not even reached the browser.
The problem is already much more specific: I need to inspect the frontend build, entry point, or asset pipeline.
If the CSS Was Built, I Open DevTools
At this point I stop changing CSS at random.
I inspect the target element in browser DevTools and check the Styles panel:
- whether my rule is present at all;
- which CSS file it came from;
- whether the declaration is crossed out;
- which selector actually wins;
- what computed value the element receives.
.my-selector { margin-top: 16px;} .some-parent .my-selector { margin-top: 0;}In this case, the first selector really did load. The build works. Cache is not the problem either.
But the second selector is more specific, so its value wins.
This is a completely different class of problem, and DevTools usually makes it visible immediately.
I Check the Stylesheet Order
.my-selector { margin-top: 16px;} /* Loaded later */.my-selector { margin-top: 0;}Even identical selectors can behave differently depending on the order in which the browser receives the CSS.
When specificity is equal, the later declaration normally wins.
That is why I look not only at the value in DevTools but also at the file and line number. This often reveals that another bundle or stylesheet loaded later is overriding my rule.
I Check Whether the Selector Matches the DOM
.purchase .status { margin-top: 10px;}<div class="purchase"> <div class="status-wrapper"> ... </div></div>This is another very simple cause that is easy to miss: the HTML may already differ from what I remember or from another template I inspected earlier.
In this example, the CSS can be syntactically correct, the build can succeed, and the bundle can load, but there is simply no .status element in the DOM.
The selector has nothing to match.
Only Then Do I Investigate Cache
Cache is a popular explanation for almost every styling problem, but I do not start there.
I first want to know that the expected rule:
- exists in the source;
- reached the compiled CSS;
- was loaded by the browser;
- matches the actual DOM.
Only after that does a hard reload or Disable cache in the Network panel become a useful next step.
rg -n "my-selector" publicIn Network I also check which exact CSS asset the browser actually loaded and inspect its Response when necessary.
If my local build contains one rule while the browser receives a different asset, then versioning, the asset manifest, CDN, or another caching layer becomes relevant.
I Do Not Use !important as the First Fix
.my-selector { margin-top: 16px !important;}When a style does not apply, it is very easy to add !important and immediately get the expected visual result.
But that does not answer the important question: why did the previous rule not work?
If the real cause is the wrong selector, another source file, an old bundle, or stylesheet order, !important only hides the problem and makes future changes harder.
I prefer to find the source of the behavior first and only then decide how the CSS should be fixed.
My Short Debugging Flow
# 1. Confirm that I changed the expected sourcegit diff -- path/to/file.scss # 2. Find every occurrence of the selectorrg -n "my-selector" resources public # 3. Inspect frontend scriptscat package.json | grep -A 20 '"scripts"' # 4. Rebuild assetsnpm run dev # 5. Confirm that the rule reached compiled CSSrg -n "my-selector" public # 6. Inspect repository statesource | vbuild | vcompiled asset | vloaded asset | vselector matches DOM | vcascade / specificity / orderAfter the terminal checks, I move to DevTools and inspect the actual DOM and CSS cascade.
The main change in my approach is simple: when a style does not apply, I no longer immediately change the CSS again.
I first identify the stage where the change disappeared.
A CSS change passes through a whole chain: source -> build -> loaded asset -> selector -> cascade -> browser. Once I find the stage where it disappeared, the problem usually becomes much simpler.
This approach can look slower than changing a margin several times and refreshing the page.
In a real project it usually saves time, because every check eliminates an entire class of possible causes.
I no longer debug CSS as a single declaration. I debug the path that declaration takes from the source file to the browser.

