Build and debug deterministic CSS Grid visualization overlays (columns, rows, gutter hatching) with subgrid support. Use when grid guides are duplicated, missing, misaligned, or inconsistent across nested layouts and route transitions.
Resources
2Install
npx skillscat add derklinke/codex-config/css-grid-overlay-debug Install via the SkillsCat registry.
SKILL.md
CSS Grid Overlay Debug
Overview
Use this skill to implement a stable, global grid-debug overlay for web layouts using CSS Grid and subgrid.
Goal: one renderer, one scene graph, deterministic output, no duplicate guides.
Use When
- User asks to visualize grid columns/rows/gutters globally.
- Current grid overlay draws duplicate lines/hatches in nested grids.
- Grid guides disappear after route transitions, DOM updates, resize, or font load.
- Subgrid layouts do not inherit or align with ancestor gutter visualization.
Do Not Use When
- Task is only visual styling (colors/typography) with no grid instrumentation.
- User needs permanent production UI overlays (this skill is debug tooling).
Canonical Architecture
- Global overlay root
- Create one fixed/absolute overlay in
document.body. - Overlay has two layers: hatches + lines.
- Never mount per-grid overlay DOM inside each grid shell.
- Single-pass render
- Collect all grid shells (
[data-site-grid-shell]), sorted outer -> inner. - Build a scene of primitives (column lines, row lines, column hatches, row hatches).
- Deduplicate/merge spans globally before paint.
- Subgrid-safe columns
- For non-subgrid shells: compute gutter spans from resolved track sizes +
column-gap. - For subgrid shells: project gutter spans from nearest ancestor non-subgrid column source.
- Do not independently invent subgrid column gutters.
- Subgrid inheritance contract: the element with
grid-template-columns: subgridmust also be the direct grid item in the parent grid. - Do not place an extra wrapper between parent grid and subgrid container; wrapper indirection breaks track inheritance and causes visual misalignment.
- Row gutters from actual content rows
- Group child boxes by row top (tolerance-based).
- Row gutter = gap between adjacent grouped rows.
- Draw hatch/lines only for real vertical gaps.
- Deterministic scheduling
- Coalesce renders with
requestAnimationFrame. - Trigger from
ResizeObserver,MutationObserver,scroll,resize, and route/page events. - Keep a single debug state flag (
data-grid-debug="on"+ cookie).
Repo-Proven Patterns (klinke.studio)
- Grid shell contract
SiteGridemits both markers on the same root:data-site-grid-shell+data-site-grid-grid.- Collector should still support fallback query (
shell.querySelector("[data-site-grid-grid]")) for nested/wrapped usage.
- Rows-only instrumentation mode
- Support
data-site-grid-rows-onlyon shell or grid element. - In rows-only mode, skip column gutter derivation but still compute row gutters and draw row guides.
- Boundary-line anti-duplication
- Draw shell perimeter guides only for top-level shells (
depth === 0). - Allow nested shells to contribute gutter hatches/lines only.
- This avoids near-duplicate boundary lines from tiny nested offsets.
- Subgrid + ancestor projection
- When
grid-template-columnsresolves tosubgrid, do not create local column gutters. - Project gutters from nearest ancestor marked as
isColumnSource. - Clamp projected gutters to current shell bounds.
- Numerical stability defaults
- Use quantization and tolerances to absorb subpixel drift:
EPS = 1.25,QUANT = 1,ROW_GROUP_EPS = 4are stable defaults in this repo.- Merge spans before paint (
mergeSpans) for both line and hatch primitives.
- Debug-state persistence + toggle sync
- Persist debug state with cookie (
klinke_grid_debug) and reflect withdata-grid-debug="on"on<html>. - Sync all
[data-grid-debug-toggle]controls viaaria-pressed+data-on. - Expose runtime API for operators:
window.__klinkeSiteGridDebug = { renderAll, setEnabled }.
- Lifecycle hooks for Astro
- Rebind toggles and rerender on
astro:page-load. - Observe DOM churn with
MutationObserver(childList/subtree/attributesandattributeFilter: ["class", "style"]). - Schedule rerender after
document.fonts.readyto handle late metric shifts.
Implementation Workflow
- Find current instrumentation:
- Search for
data-site-grid-shell,data-site-grid-grid, existing debug scripts, and per-shell guide layers.
- Remove per-shell paint logic:
- Keep shell markers, remove shell-local guide DOM/layers.
- Ensure only one global overlay owns guide rendering.
- Build metric collectors:
- Bounds, track sizes, column gaps, row grouping.
- Subgrid detection from computed
grid-template-columns. - Verify DOM structure for every subgrid shell:
- subgrid node is direct child/grid-item of parent grid
- no intermediate wrapper between parent grid and subgrid node
- Add primitive dedupe:
- Quantize coordinates (small step, e.g.
0.5px). - Merge overlapping spans by axis key.
- Render scene:
- Paint merged hatches first, lines second.
- Use consistent masks for dotted lines + hatch orientation.
- Wire observers/events:
- Route transitions (
astro:page-loador framework equivalent). - DOM mutations, resize, scroll, fonts ready.
- Expose debug API:
window.__klinkeSiteGridDebug = { renderAll, setEnabled }.
Reliability Rules
- One overlay root only.
- No per-shell
replaceChildrenrendering. - No recursive paint dependencies between nested shells.
- No mixed coordinate spaces (always normalize to document coordinates).
- Always merge spans before DOM paint.
Quick Validation Checklist
- Toggle on/off repeatedly: no ghost lines remain.
- Nested grid + subgrid page: no duplicated column lines.
- Nested subgrid uses parent tracks exactly (no column drift/offset between parent and subgrid content).
- Deep content page: row gutters align to real row gaps.
- Scroll + resize + route navigation: overlay remains aligned.
- Font load/late content insertion: guides update once, no jitter.
- Rows-only shell (
data-site-grid-rows-only) renders row guides without column guides.
References
- Primary specs/docs:
references/primary-sources.md
Local Cross-References
design-system-doc- Use when grid behavior should become a durable design rule.