CSS Edge Cases
Layout quirks, animation gotchas, and browser inconsistencies
Start Here
Essential reads to understand the key concepts and patterns.
CSS :has() — The Parent Selector That Changes Everything
Finally select parents based on children. Use :has() for conditional styling, previous sibling selection, and patterns that previously required JavaScript.
CSS Container Queries Edge Cases: When @container Silently Fails
Container queries are here, but containment types and the ancestor lookup algorithm create subtle traps. Here's what breaks and how to fix it.
The 16 Ways CSS Creates Stacking Contexts
z-index: 9999 still behind? Stacking contexts are the reason. Opacity, transform, filter, and 12+ other properties silently create them—trapping your elements.
CSS Cascade Layers & !important: The Specificity Inversion
Normal layers: last wins. Important layers: FIRST wins. Learn why !important inverts layer priority.
CSS Scroll-Driven Animations: When animation-timeline Breaks Your Layout
The animation shorthand silently resets your scroll timeline. Plus: main thread demotion, inactive timelines, and stacking context surprises.
More Articles
CSS color-mix() for Dynamic Theming
Blend colors at runtime without preprocessors—tints, shades, and alpha variations directly in CSS.
CSS light-dark(): Theme Colors Without the Gotchas
Theme-aware colors in pure CSS — but only if color-scheme is set, inherited correctly, and browsers actually support it.
CSS @scope: Native Style Scoping Without Shadow DOM
Native CSS scoping with upper AND lower boundaries — finally, component isolation without Shadow DOM or naming conventions.
CSS field-sizing: Auto-Growing Inputs Without JavaScript
Auto-growing textareas and inputs without JavaScript—finally native in CSS. One property replaces ResizeObserver hacks.
CSS Native Masonry Layout: The End of JS Grid Libraries
Native CSS masonry finally replaces JavaScript grid libraries. grid-template-rows: masonry packs items into the shortest column—no JS, no layout thrashing.
CSS sibling-index() and sibling-count(): Dynamic Sibling Styling
Finally—style elements based on their position among siblings without JavaScript. Staggered animations, rainbow colors, and dynamic layouts in pure CSS.
CSS text-wrap: balance and pretty
balance equalizes headline line lengths. pretty prevents orphans in paragraphs. Both eliminate decades of typography hacks with pure CSS.
CSS @starting-style: Entry Animations Without JavaScript
Animate elements appearing from display: none using @starting-style—pure CSS entry transitions without JavaScript timing hacks.
CSS @property: Finally Animating the Un-animatable
Declare custom property types with @property to unlock gradient, color, and numeric animations
CSS @property Animation: The Compositor Can't Help You
Typed custom properties enable smooth interpolation but force main-thread animation—here's what to watch for
CSS Subgrid Browser Inconsistencies: Cross-Browser Patterns
Subgrid works everywhere now, but Chrome, Firefox, and Safari disagree on gaps, auto-sizing, and named lines. Here's what to watch for.
CSS contain: Render Isolation for Performance
Tell browsers 'this element is independent' with CSS contain. Layout, paint, and style calculations get scoped to the subtree—potentially cutting layout costs by 80%+.
CSS Anchor Positioning: Tooltips Without JavaScript
CSS Anchor Positioning eliminates JavaScript tooltip libraries. One anchor-name, one position-anchor, and the browser handles collision detection.
content-visibility: The Searching & Scrolling Problem
Skipping layout boosts performance but breaks scrollbars—use contain-intrinsic-size: auto to fix the jump
Safari Animation Artifacts: The 1px Black Line Glitch
Fix the jagged edges and flickering lines on expanding images with outline: 1px transparent
CSS Inset: The Modern Shorthand for Positioning
Stop writing top/right/bottom/left—use inset to handle all four offsets in a single line
Respecting User Motion Preferences with prefers-reduced-motion
Don't just remove animations—replace motion with opacity to preserve context while respecting accessibility
Background Bleed: The Subpixel Rendering Bug
Why border-radius sometimes leaves a gap between background and border, and how background-clip fixes it
CSS Animations vs Figma: Production Reality vs Design Prototypes
Figma's spring physics can't translate to CSS cubic-bezier—understand the gap between design and code
Animating CSS Grid: The Discrete Value Problem
grid-template-columns won't animate—fr units lack computable intermediate values, breaking smooth transitions
CSS Animations vs JavaScript: Layout Thrashing and the FLIP Technique
JavaScript animations cause layout thrashing—learn CSS tricks and FLIP to keep animations compositor-safe
Font Metrics: Why Text Won't Center in Buttons
Invisible bounding boxes in fonts cause alignment issues—learn to fix them with CSS overrides
Font Loading: The FOUT, FOIT, and CLS Dilemma
font-display values force a choice between fast rendering and layout stability—understand the trade-offs
size-adjust: Eliminating Font Swap Layout Shifts
Match fallback font metrics to custom fonts and eliminate 90% of CLS from font loading
OpenType Features: Ligatures, Tabular Numbers, and Small Caps
font-feature-settings doesn't cascade—it replaces. Learn the high-level font-variant-* alternatives
Font Preloading: When rel=preload Backfires
Missing crossorigin causes double downloads; too many preloads delay LCP—use surgically
Font Synthesis: Avoiding Fake Bold and Italic
Prevent browsers from creating fake font variants and ensure professional typography
Dynamic Fonts in Web Development
Master custom typography with @font-face and variable fonts for better design flexibility