Grid Architecture
The Verbiage
The Why
Fixed positioning causes layout overlaps because it removes elements from the document flow. When a sidebar uses position: fixed, it no longer occupies space in the layout, causing the main content to slide underneath it. This requires padding hacks like pl-64 to compensate, which break on different screen sizes and create maintenance nightmares.
We use a CSS Grid Shell to ensure the sidebar and main content never collide. CSS Grid creates dedicated tracks that each element occupies, preventing any overlap regardless of content size or screen width.
The Verbiage
Grid Track: A column in the CSS Grid layout. The first track is 260px wide for the sidebar, the second track (1fr) takes the remaining space for main content. Each track is a reserved space that no other element can invade.
Sidebar Constraint: The sidebar is constrained to its 260px grid track using lg:sticky positioning, not lg:fixed. This keeps it within the document flow while remaining visible during scroll. The sticky positioning respects the grid track boundaries.
Fluid Main: The main content area uses 1fr (fractional unit) to fill all remaining horizontal space after the sidebar track, creating a responsive layout that adapts to any screen width. The 1fr unit means "take all available space" after fixed-width tracks are calculated.
This pattern ensures zero overlap because each element has a reserved grid track, and the browser's grid engine handles all spacing automatically—no padding hacks needed.
The Blueprint
// components/layout-wrapper.tsx
"use client";
import { usePathname } from "next/navigation";
import { Sidebar } from "@/components/sidebar";
import { LibrarySidebarNav } from "@/components/library-sidebar-nav";
import { SidebarProvider, useSidebar } from "@/components/sidebar-context";
import { Header } from "@/components/header";
import { getSidebarConfig } from "@/lib/sidebar-config";
function LayoutContent({ children }: { children: React.ReactNode }) {
const { sidebarOpen, setSidebarOpen } = useSidebar();
const pathname = usePathname();
const isLibraryPage = pathname.startsWith("/library");
const config = getSidebarConfig(pathname);
const hasSidebar = config && config.links.length > 0;
return (
<>
{/* Header spans full width above the grid */}
<Header />
{/* Grid Shell: Sidebar + Main Content */}
{/* The grid creates two tracks: 260px for sidebar, 1fr for content */}
<div className={hasSidebar ? "lg:grid lg:grid-cols-[260px_1fr]" : ""}>
{/* Sidebar - First Grid Column (260px track) */}
{hasSidebar && (
isLibraryPage ? (
<LibrarySidebarNav />
) : (
<Sidebar open={sidebarOpen} onOpenChange={setSidebarOpen} />
)
)}
{/* Main Content - Second Grid Column (1fr track) */}
<main className="w-full">{children}</main>
</div>
</>
);
}
export function LayoutWrapper({ children }: { children: React.ReactNode }) {
return (
<SidebarProvider>
<LayoutContent>{children}</LayoutContent>
</SidebarProvider>
);
}The AI Context
The CSS Grid Shell pattern uses `lg:grid lg:grid-cols-[260px_1fr]` to create two columns. The sidebar uses `lg:sticky lg:top-0 lg:h-screen` (NOT `lg:fixed`). The main content uses `w-full` in the second grid column. Never use `lg:fixed`, `lg:inset-y-0`, or `lg:pl-64` padding hacks. The grid handles all spacing automatically.Directive for AI Agents
Copy and paste this directive to instruct an AI assistant on how to maintain this specific pattern:
## Directive for AI Agents
When modifying the layout, do not use absolute/fixed positioning for main containers. Refer to the grid-cols mapping in the root layout to maintain the 260px sidebar track.
**Required Pattern:**
- Container: `lg:grid lg:grid-cols-[260px_1fr]`
- Sidebar: `lg:sticky lg:top-0 lg:h-screen` (first grid track)
- Main: `w-full` (second grid track, 1fr)
**Forbidden Patterns:**
- ❌ `lg:fixed` positioning
- ❌ `lg:absolute` positioning
- ❌ `lg:pl-64` or padding hacks
- ❌ `lg:inset-y-0` positioning
The grid track system ensures zero overlap and automatic spacing.