PLAINFINCH learn by building

Debugging CSS

You will be able to work out step by step why some CSS does not apply, and fix common bugs like leaking margins.

What is a good method for CSS bugs?

Most CSS bugs come from a short list of causes, and checking them in a fixed order is faster than changing values at random. Pick one element that looks wrong and one property that should be different, then ask five questions.

First, is the rule matching? Check the selector against the HTML: a typo in a class name, a missing dot, a space where there should be none. Second, is it overridden? Another rule may win through specificity, source order or a later layer. Third, is the value valid? A misspelled property or a missing unit makes the browser drop the line. Fourth, is it inherited, or should it be? A child with its own colour ignores the parent's. Fifth, is something else in the way: a parent with overflow: hidden, a stacking context, a sibling taking space?

Fix one thing at a time and confirm each change. Three edits at once may fix the bug and add two new ones you will not notice.

FigureA five-step debugging flow from left to right: is the rule matching, is it overridden, is the value valid, is it inherited, is something else in the way. When a step shows a problem, its arrow points down to the tool that reveals it; otherwise go on to the next step.A five-step debugging flow from left to right: is the rule matching, is it overridden, is the value valid, is it inherited, is something else in the way. When a step shows a problem, its arrow points down to the tool that reveals it; otherwise go on to the next step.
Ask five questions in order. Each one points to a tool: the selector, the Why? lens, the invalid-value warning, the Computed panel, and the Box lens or Layout panel.

How do the Why? and Box lenses help?

The editor's Why? lens answers the first four questions for the element under your cursor. It lists every rule that matched, shows which declaration won and why (specificity, order or layer), crosses out the losers, and flags values the browser rejected. If your rule is not in the list at all, the selector does not match.

The Box lens draws the content, padding, border and margin of an element. It is the quickest way to see margin collapse, unexpected padding, or a box much wider than you expected. Margins drawn outside a parent's background are a sign they have collapsed through it.

Which DevTools panels should you use?

Every desktop browser has the same three panels under different names. Right-click the element and choose Inspect.

The Styles pane shows matching rules in winning order, crosses out overridden declarations, and puts a warning icon next to invalid ones. You can toggle declarations with checkboxes and edit values live. The Computed pane shows the final value of each property and, when expanded, which rule produced it; use it for inherited values like font-size and color. The Layout pane, and the badges next to flex and grid containers, draw grid lines, gaps and flex directions on the page.

Changes in DevTools are lost on reload. Copy the working declaration back into your stylesheet before you refresh.

Why do margins collapse, and how do you stop it?

In normal block layout, vertical margins that touch combine into one margin, the larger of the two. Between siblings this is useful: a paragraph with margin-bottom: 16px followed by one with margin-top: 24px gets a 24px gap, not 40px.

Between a parent and its first or last child it surprises people. If the parent has no top padding, border or other separation, the child's top margin passes through the parent's edge and pushes the parent down instead. The background starts lower and a white strip appears above it, as in the demo.

There are three clean fixes. Give the parent display: flow-root, which starts a new block formatting context so child margins stay inside. Give the parent some padding. Or make the parent a flex or grid container and use gap for spacing between children, since margins never collapse in flex and grid layout. Avoid overflow: hidden as a fix: it works, but it also clips focus rings and shadows.

.hero {
  display: flow-root;
}

.stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

Why does z-index not work?

Two reasons cover nearly every case. z-index only affects positioned elements (any position other than static) and flex or grid items. On a plain block it does nothing, and DevTools shows the declaration without crossing it out, which hides the problem.

The second reason is stacking contexts. An element with opacity below 1, a transform, a filter, or a positioned element with a z-index creates its own stacking context. Children inside it can only be ordered within it. A dropdown with z-index: 9999 inside a header with z-index: 1 stays below a main area with z-index: 2. Raise the z-index on the header, the element that actually competes, and keep numbers small and documented.

How do you find what causes horizontal scroll?

A page that scrolls sideways on a phone has at least one element wider than the viewport. Common culprits are a fixed width in pixels, an image without max-width: 100%, a long URL or word that cannot wrap, a 100vw element on a page with a vertical scrollbar, and negative margins.

To find it, add a temporary outline to everything. Outlines take up no space, so they reveal every box without moving anything. Scroll right and look for the box that sticks out. In DevTools you can also run document.querySelectorAll('*') in the console and filter for elements whose right edge is beyond the window width.

Fix the cause instead of hiding it. overflow-x: hidden on body hides the scroll but also clips content and breaks position: sticky on descendants.

* {
  outline: 1px solid red;
}

What other classic problems should you recognise?

Most bugs you meet repeat. Learning their signatures saves the most time:

  • Centering: for one item, use display: grid; place-items: center; on the parent. margin: 0 auto only centres a block that has a width narrower than its parent, and text-align: center only centres inline content.
  • A gap under images: images are inline and sit on the text baseline. display: block on the image, or vertical-align: middle, removes it.
  • 100vh on phones: mobile browsers measure vh against the largest viewport, with the address bar hidden. Use 100dvh for the visible height, with a 100vh line before it for very old browsers. All current browsers support dvh.
  • Percentage heights that do nothing: height: 50% needs a parent with a definite height. Use min-height, flex or grid instead.
  • A rule that never applies: check for a missing } earlier in the file. The browser treats everything after it as part of the broken rule.

How should you read AI-generated CSS?

AI tools produce CSS that looks finished but often hides problems. Read it with the same five questions, and look for these patterns.

Duplicated rules: the same selector appears three times with slightly different values, so the last one wins and the others are dead weight. Merge them. !important everywhere: a sign the tool fought the cascade instead of understanding it. Remove them and fix the selectors or the layer order. Magic numbers: top: 37px, margin-left: -13px, width: 312px. They make the layout work at one screen size only. Replace them with flex or grid alignment, gap, and relative units.

Also check for properties that do nothing in context, such as z-index on a static element, justify-content on a block, or vertical-align on a div. The Why? lens flags many of these. Delete what does nothing; a shorter stylesheet is easier to debug next time.

Field notes

  • Check a short list of causes in a fixed order instead of changing values at random.
  • The browser's Styles pane shows matching rules and which declarations lost.
  • Touching vertical margins combine, and a child's margin can leak out of its parent.
  • display: flow-root on the parent keeps a child's margin inside it.

Easy to get wrong

z-index has no effect on a static block. Give it a position, or make it a flex or grid item.

Hiding overflow on the body masks the bug and breaks sticky elements. Find the wide element and contain it.

!important wins this fight and makes every later change harder. Fix the specificity or the layer order.

On phones 100vh is taller than the visible area, and a fixed height cuts off content that grows.

Questions people ask

Why is my CSS not updating at all?

Check that the file is linked, the path is right and the browser is not serving a cached copy. A hard reload, or DevTools with the cache disabled, rules out caching.

What does a crossed-out declaration mean in DevTools?

Another declaration for the same property won. Hover it or check the Computed pane to see which one.

What does a warning icon mean?

The browser could not parse the property or value, so it ignored that line. Look for spelling mistakes and missing units.

Is margin collapse a bug?

No. It is defined behaviour of block layout. It does not happen in flex or grid layout, or across a box with padding or a border.

Keep going