一键导入
frontend-page-layout
Use when creating page layouts, handling height calculations, or structuring page components with flex/grid
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when creating page layouts, handling height calculations, or structuring page components with flex/grid
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | frontend-page-layout |
| description | Use when creating page layouts, handling height calculations, or structuring page components with flex/grid |
This skill defines layout structure patterns for page components to ensure consistent height calculations and prevent overflow issues.
The application uses a two-tier layout system:
__root.tsx) - Minimal, just renders <Outlet />_protected.tsx) - Handles authentication and provides sized containerKey Pattern:
// _protected.tsx:56
<div style={{ height: "calc(100vh - 48px)" }}>
<Outlet />
</div>
This creates a container that fills the viewport minus the 48px global Nav.
Page components receive a pre-sized container from the protected layout.
CRITICAL RULE: Pages MUST use height: 100%, NEVER recalculate viewport.
// ✅ CORRECT - Page component
export const Page_Example = () => {
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
{/* Page content */}
</div>
);
};
// ❌ WRONG - Recalculating viewport
export const Page_Example = () => {
return (
<div style={{ height: "calc(100vh - 44px)", display: "flex", flexDirection: "column" }}>
{/* This WILL cause overflow! */}
</div>
);
};
// ✅ Page container - inherit from parent
<div style={{ height: "100%" }}>
// ✅ Main content area - grow to fill remaining space
<div style={{ flex: 1, overflow: "hidden" }}>
// ✅ Fixed-height secondary nav
<div style={{ height: 44 }}>
// ❌ NEVER do this in page components
<div style={{ height: "calc(100vh - 44px)" }}>
<div style={{ height: "calc(100vh - 48px)" }}>
<div style={{ height: "100vh" }}>
// ❌ NEVER hardcode pixel heights matching viewport calculations
<div style={{ height: "1032px" }}> // Viewport-derived value
Single Source of Truth:
Nav.tsx:80)calc(100vh - 48px) (defined in _protected.tsx:56)height: 100% (inherit from container)Why This Matters:
If the Nav height changes to 50px:
_protected.tsx only → All pages automatically adjustcalc(100vh - 48px) → Must update every page manuallyCommon pattern for pages with secondary navigation:
export const Page_Example = () => {
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
{/* Fixed-height secondary nav */}
<SecondaryNav height={44} />
{/* Main content - fills remaining space */}
<div style={{ flex: 1, overflow: "hidden" }}>
<PanelGroup direction="horizontal">
{/* Panels handle their own sizing */}
</PanelGroup>
</div>
</div>
);
};
Key Elements:
height: 100% + flex columnflex: 1 + overflow: hiddenBorders add to element dimensions. Use box-sizing: border-box (usually already global).
// ✅ Border included in height calculation
<div style={{
height: 44,
borderBottom: `1px solid ${token.colorBorder}`,
boxSizing: "border-box" // Usually global, explicit here for clarity
}}>
// ❌ Border adds 1px to height
<div style={{
height: 44,
borderBottom: `1px solid ${token.colorBorder}`,
boxSizing: "content-box" // Avoid this
}}>
File: spark/frontend/my-vite-app/src/pages/Page_Set/Page_Set.tsx
export const Page_Set = () => {
return (
<Provider_Page_Set>
{/* ✅ height: 100% - inherits from _protected container */}
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
{/* Fixed-height secondary nav (44px) */}
<PageSet_Nav setId={setId} />
{/* Main content fills remaining space */}
<div style={{ flex: 1, overflow: "hidden" }}>
<PanelGroup direction="horizontal">{/* Resizable panels */}</PanelGroup>
</div>
</div>
</Provider_Page_Set>
);
};
export const Page_Bad = () => {
return (
// ❌ WRONG - Recalculating viewport height
<div style={{ height: "calc(100vh - 44px)", display: "flex", flexDirection: "column" }}>
<SecondaryNav />
<MainContent />
</div>
);
};
Why This Breaks:
_protected.tsx provides calc(100vh - 48px) containercalc(100vh - 44px) = 4px overflow// ❌ DON'T recalculate viewport
<div style={{ height: "calc(100vh - 44px)" }}>
// ✅ DO inherit from parent
<div style={{ height: "100%" }}>
// ❌ DON'T hardcode viewport-based heights
<div style={{ height: "1032px" }}> // Someone calculated viewport - 48px
// ✅ DO use relative heights
<div style={{ height: "100%" }}>
// ❌ DON'T forget overflow handling
<div style={{ flex: 1 }}>
<PanelGroup> {/* May overflow container */}
// ✅ DO constrain overflow
<div style={{ flex: 1, overflow: "hidden" }}>
<PanelGroup> {/* Contained within bounds */}
// ❌ DON'T mix calculation strategies
<div style={{ height: "calc(100vh - 48px)" }}>
<div style={{ height: "100%" }}> {/* Which 100%? Confusing! */}
// ✅ DO use consistent relative heights
<div style={{ height: "100%" }}>
<div style={{ flex: 1 }}> {/* Clear hierarchy */}
If you see unexpected vertical scroll:
Check page container height:
height: 100%calc(100vh - Xpx) → Replace with 100%Check parent layout:
_protected.tsx should provide sized containerCheck borders:
box-sizing: border-box should be globalCheck nested content:
flex: 1 + overflow: hidden for main content// Column layout with fixed header + flexible content
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
<Header height={44} />
<Content flex={1} overflow="hidden" />
</div>
// Row layout with sidebar + main area
<div style={{ height: "100%", display: "flex", flexDirection: "row" }}>
<Sidebar width={250} />
<Main flex={1} overflow="auto" />
</div>
<div
style={{
height: "100%",
display: "grid",
gridTemplateRows: "44px 1fr", // Fixed header + flexible content
}}
>
<Header />
<Content />
</div>
When creating a new page component:
height: 100% (not viewport calculations)display: flex with flexDirection: columnflex: 1 + overflow: hiddencalc(100vh - Xpx) anywhere in page componentUse when deploying Cloudflare Workers, managing R2 storage, or working with Cloudflare infrastructure
Use when working with ANTD components, theme tokens, icons, forms, or feedback components (message/notification/modal)
Use when adding, referencing, or serving static assets (images, fonts, videos, 3D models) through the R2 CDN pipeline with type-safe imports
Use when writing or reviewing JavaScript/TypeScript code for style patterns like concise arrows, inline handlers, expression formatting, or when tempted to use eslint-disable
Use when working with environment variables in frontend code
Use when creating or modifying keyboard shortcuts/hotkeys in frontend code