The CSS debugging hell I used to live in
Ten years ago my CSS debugging workflow was basically:
- Add a red border.
- Add another red border.
- Toggle random
position: relativeand hope the layout stops exploding.
I spent half my day trapped between Chrome DevTools and an editor, fighting layout bugs with guesswork. No structure. No repeatable flow.
Today my browser devtools setup feels like a proper instrument instead of a fire extinguisher. I can usually answer “why is this broken?” in under a minute, even in gnarly codebases I did not write.
This is the workflow I wish someone had handed me a decade ago. It is very specific. It is not perfect. It just works for me on real projects.
Rule zero: DevTools is the source of truth
I used to treat my editor as the source of truth. That was a mistake.
Now I assume the browser is right and everything else is lying. Design tool, Tailwind class soup, some legacy LESS file in a folder called old/old2. All liars.
The first question I always answer is:
What CSS is actually applied to this element right now?
I always start with Elements panel, not the codebase.
Step 1: Click the thing that is wrong, not the thing you think is wrong
My old mistake: click some parent I assumed was responsible. Tweak margins. Everything gets worse.
Now I always do this:
- Open DevTools (
Cmd+Opt+Ion Mac,Ctrl+Shift+Ion Windows/Linux). - Hit the element picker (
Cmd+Shift+Cor the cursor icon). - Hover until I see the highlight overlay show exactly the wrong bit of UI.
- Click that.
Sounds stupidly simple, but it forces me to target the actual painted box, not my mental model of the DOM.
Step 2: The layout box model overlay is my compass
Once I have the right node selected, I look at the layout box model like it is a compass.
In Chrome and Edge this shows up in the Styles panel as the box diagram: content, padding, border, margin. Firefox has a similar layout box in its Layout tab. I stare at that before I touch anything.
There are three questions I answer immediately:
- Is this element the size I expect?
- Is the spacing coming from this element or its neighbors?
- Is it
display: block,flex,grid, or something else?
If I do not know those three answers, I do not edit styles yet. That rule alone has saved me hours.
Layout inspector: the flex and grid truth serum
Flexbox and Grid used to feel like black magic. Beautiful when it worked. Cruel when it did not.
Now I treat the layout inspector as non‑optional. You get different UI in different browsers, but the idea is the same.
Debugging flexbox without losing your mind
My flex flow roughly looks like this:
- Select the flex container, not the child.
- In Chrome: check the Layout panel. Toggle the Flexbox overlay for that container.
- In Firefox: open the Layout tab and look under Flexbox for the selected node.
- Visually confirm the direction, gap, and alignment lines that appear on the page.
The overlay lines instantly show which axis is main vs cross, and how free space is distributed. That kills 80 percent of "why is this hugging the wrong side" questions.
Two flex moves I repeat a lot:
- Kill accidental height stretching: set
align-items: flex-starton the container in DevTools and see if the layout suddenly matches the design. - Check flex-basis overrides: watch for
flex: 1or weirdflex-basisin the Styles panel, especially coming from a utility class.
If a component looks almost right but sizing is off, I highlight each child node and watch the box model update. That shows which one is absorbing the extra space.
Grid inspector: stop guessing track sizes
Grid is worse to debug if you do it mentally. I basically refuse to debug grid without the inspector open.
Flow:
- Select the grid container.
- Turn on the Grid overlay.
- Look at the track labels and line numbers right on the page.
I immediately look for three things:
- Are tracks the size I think they are?
1fris often not doing what I assumed. - Is there an implicit row or column I forgot existed?
- Is
align-contentorjustify-contentpushing everything to a weird spot?
If something overlaps or disappears, I check the grid area assignments in the Styles panel. The overlay will show which cell the child thinks it lives in. Reality beats imagination every time.
Cascade debugging: stop scrolling, start filtering
Ten years ago I would scroll the entire Styles panel like a raccoon in a dumpster, hunting for one bad property. I do not do that anymore.
Now I rely heavily on two things: filtering and cascade order.
Filter for the property, not the file
If spacing is off, I type margin or gap into the Styles search filter. Chrome and Firefox both support filtering CSS properties in the Styles pane.
Instantly I see every margin that touches this element, where it comes from, and which ones are crossed out. Same for things like display, position, z-index, or font.
This has changed how I read CSS. I very rarely care which file defined the rule first. I care which rule won.
Watch for the crossed-out lies
Crossed out rules are DevTools whispering the truth. Something like:
- A utility class overrode your component styles.
- A media query later in the cascade killed your mobile layout.
- An inline style from JavaScript is taking priority.
I scroll until I find the first active version of the property. That is the boss. Everything above, crossed out, is historical fiction.
If I am debugging someone else’s Tailwind setup, this is critical. One utility at the bottom is often fighting a handful of "global" component styles higher in the cascade. The Styles panel tells you who actually won.
Layout shifts and overflow: paint what you can see
Another trick that 2014-me did not have: I now debug layout shifts and overflow early instead of when QA screams.
Highlights for scrollable and overflow
In Chrome’s Layout panel there is a section for Scroll and Overflow. I toggle Show scroll performance issues and Scroll containers. That paints outlines around things that scroll.
Similarly, I sometimes temporarily slap overflow: visible !important or overflow: hidden !important on a parent via DevTools to see which way the content wants to escape.
If I still cannot see where something goes, I give the problematic child a temporary background: rgba(255,0,0,.2) right in DevTools. Then I scroll and resize. You quickly spot unexpected wrapping or a rogue height limitation.
The Layers panel: when CSS spills into rendering
Modern UIs push the browser hard. Complex animations, scroll effects, fixed headers, zoomed backgrounds. At some point CSS debugging stops being just about selectors and becomes about how the browser actually paints.
This is where the Layers panel finally got a permanent spot in my workflow.
Why I even opened Layers the first time
I hit a bug on a marketing page I built: a sticky header with backdrop blur was stuttering badly on scroll, but only on low-end devices. Classic “works on my machine” trap.
CPU profiling told me nothing interesting. JS was not the problem. So I opened Chrome DevTools, hit the Performance tab, recorded a scroll, then switched to the Layers view for that recording.
What I saw looked like a lasagna of composited layers. The sticky header had forced its own layer, plus every blurred background section behind it had its own. The GPU was juggling too many big textures every frame.
That moment sold me on using Layers for CSS issues that smell like performance.
How I read the Layers panel now
My Layers workflow is pretty simple:
- Open the Performance panel.
- Record a realistic interaction: scroll, hover, open a menu.
- Stop recording and click into the Layers sidebar.
- Look for large layers that move relative to each other.
I care about three things:
- Which elements force their own layer? Things with
transform,filter,position: fixed,will-change, and some animations. - Are we repainting huge textures constantly? Big full-bleed sections, parallax stuff, videos.
- Is a small animated element in the same layer as a massive static background? That is often where jank starts.
Then I go back to Styles on the offending nodes and ask: can I reduce filter usage, simplify backdrop-filter, or avoid unnecessary will-change that forced extra layers.
I have literally fixed “laggy scroll” tickets by removing a single will-change: transform from a container that did not need it. Without Layers, I would have blamed React or the router or whatever else looked scary.
Persistent tools: never start from zero
One thing that speeds this flow up: I keep certain DevTools panels permanently visible.
My default layout in Chrome
This is what I use on my main machine:
- Left side: Elements, Console.
- Right side drawer: Layout, Layers, and sometimes Network.
- Docked to the right, not bottom, to see responsive layouts better.
I pin the Layout panel, because I want flex and grid overlays one click away. I pin Layers, because performance regressions appear out of nowhere at weird times.
I also enable the "Enable advanced paint instrumentation" flag when I am deep into rendering issues. That is rare, but when a scroll animation stutters, those extra details in Performance and Layers are gold.
Firefox as a CSS-focused secondary browser
I think Firefox’s CSS tooling is still underrated. Its layout and grid inspectors are extremely visual. When I get stuck in Chrome, I often copy the URL, open Firefox, and use its Layout tab to get a fresh view.
That outweighs any minor engine differences for most layout issues. Two different inspectors give me two slightly different mental models of the same bug.
Keyboard muscle memory that actually matters
I do not memorize many shortcuts. I only care about the ones that support this flow:
Cmd+Opt+I/Ctrl+Shift+Ito toggle DevTools.Cmd+Shift+C/Ctrl+Shift+Cfor the picker.Escto toggle the bottom drawer (for quick Console under Elements).Cmd+Fin Elements to search for a class or text snippet when I am lost.
Everything else I am happy to click. I am debugging, not playing Vim on hard mode.
Bringing it together: a typical CSS bug
Here is how this actually plays out on a random bug I hit last month.
Bug report: “The CTA button on mobile overlaps the footer copy sometimes.” Helpful. Love it.
My sequence:
- Resize the browser to the reported breakpoint.
- Open DevTools, use the picker, click directly on the overlapped CTA text.
- Look at the box model to see if the button or the footer is mis-sized.
- See that the CTA is in a flex container that is
align-items: centerwith a fixed-height parent. - Open Layout panel, enable flex overlay on the parent.
- Spot that the content is taller than the parent height at certain text lengths.
- Filter Styles for
heightandmin-height. See a crossed-outmin-heightfrom a mobile media query. - Realize a later rule reintroduced a hard
heightfor a different breakpoint, which leaks into this one.
Fix was simple: remove the hard height, rely on padding and align-items: flex-start. But that only felt obviously right because the overlays and crossed-out rules told a clear story in under a minute.
Why this would have saved 2014-me so much pain
Ten years ago I treated DevTools like an inspector. Look, do not touch. Poke around, then go back to the editor and guess.
Now I treat DevTools as the primary place I reason about layout, cascade, and rendering. The codebase comes second. I prototype fixes right in the browser, using Flex/Grid overlays, cascade filtering, and the Layers panel as my guide.
If you are still sprinkling random borders and scrolling through endless CSS files, try flipping that mental model. Start from the element. Use the layout inspector as your map. Use Layers when things feel janky instead of magical.
The browser already knows exactly why your CSS is broken. The trick is just learning how to get it to talk.
Subscribe to my newsletter to get the latest updates and news
Member discussion