Common CSS bugs and gotchas — a field reference
Every bug in this lesson has already been explained mechanically somewhere earlier in this domain — this is the field-reference version, the shape each one actually takes in real code, so it's recognizable on sight instead of requiring the mechanism to be re-derived from scratch every time.
3 min read
Bug 1: the collapsing-margin gap that's smaller than expected
.paragraph { margin-bottom: 20px; }
.paragraph + .paragraph { margin-top: 30px; }
/* Actual gap: 30px (the LARGER of the two), not 50px — adjacent vertical margins collapse */Covered mechanically in the box-model lesson: adjacent vertical margins on block-level elements merge into a single margin equal to the larger of the two, never adding together. The fix: when a precise, additive gap is actually needed, use gap on a flex/grid container (which never collapses) instead of relying on adjacent margins.
Bug 2: the sidebar that's wider than its declared width
.sidebar { width: 250px; padding: 20px; border: 1px solid #ccc; }
/* Actual rendered width: 250 + 20*2 + 1*2 = 292px, not 250px */Covered mechanically in the box-model lesson: content-box (the default) adds padding and border on top of the declared width instead of including them. The fix: box-sizing: border-box globally, so declared width is always the total rendered width.
Bug 3: the z-index that "isn't working" no matter how high it goes
.parent { position: relative; z-index: 1; }
.child { position: absolute; z-index: 9999; } /* still loses to an UNRELATED sibling with z-index: 2 */Covered mechanically in the stacking-context lesson: z-index only compares within the same stacking context, and .parent's own z-index: 1 traps .child's 9999 inside it, comparing only against .parent's own siblings. The fix: raising the number never helps a trapped value — find and address the ancestor creating the unwanted stacking context instead.
Bug 4: removing the focus outline, breaking keyboard navigation
:focus { outline: none; } /* removes the ONLY visual indicator keyboard-only users have */Covered mechanically in the accessibility lesson: this is a genuinely common, genuinely damaging mistake, since a removed focus indicator makes every interactive element unusable for keyboard-only navigation. The fix: :focus-visible with a real, styled-but-visible indicator, which shows for keyboard nav specifically while suppressing the unwanted mouse-click outline.
Bug 5: layout thrashing from interleaved reads and writes
elements.forEach((el) => {
el.style.width = box.offsetWidth + "px"; // read, then write, on EVERY iteration
});Covered mechanically in the CSS-performance lesson: reading a layout-dependent property forces a synchronous layout recalculation, and interleaving reads with writes in a loop forces this on every single iteration. The fix: batch all reads first, then batch all writes — one layout pass for the whole operation instead of one per element.
Bug 6: the animation that's smooth on a laptop, janky on a phone
.card:hover { width: 320px; margin-left: -10px; } /* triggers LAYOUT on every animation frame */Covered mechanically in the transitions-and-animations lesson: width/margin are layout-triggering properties, expensive to recompute on every single frame of an animation. The fix: achieve the same visual result with transform: scale() or translate(), which the GPU compositor handles far more cheaply.
The actual throughline across all six
Every one of these traces back to the same handful of mechanisms this domain already covered in depth: the box model's precise layer-by-layer measurement rules, the cascade's context-scoped comparisons (stacking contexts included), and the rendering pipeline's three stages with genuinely different costs. Recognizing a bug's shape on sight — "this smells like margin collapsing," "this smells like a trapped stacking context" — is what separates fixing a CSS layout issue quickly from re-deriving these mechanisms from first principles every single time one shows up.
Further reading
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why does a sidebar with `width: 250px; padding: 20px; border: 1px solid` render at 292px, not 250px?
2. Why does raising a trapped z-index to an extremely high value never fix a layering bug?
3. What's the actual throughline connecting all six bugs in this field-reference lesson?