09abf45c13
- Defines height propagation chain for all pages - Establishes PageLayout → QueryBoundary → Content pattern - Documents KsSplitter master-detail implementation - Includes verification checklist for new pages - Rationale: flex children need 'min-height: 0' to respect parent constraints
4.5 KiB
4.5 KiB
ADR: Layout Height Propagation Standard
Status: ACCEPTED
Date: 2026-08-16
Authors: Claude Code
Context
Multi-level frontend layouts (PageLayout → QueryBoundary → content) require explicit height propagation to ensure:
- Single-screen principle: First load fits viewport without scroll
- Internal scrolling: Only nested containers scroll, not the page
- Consistent behavior: All pages follow the same height rules
Previous bugs stemmed from missing flex: 1; min-height: 0; constraints at various levels.
Decision
Establish a required height propagation chain for all pages:
PageLayout (.ks-page__content)
├─ height: 100%
├─ min-height: 0
└─ display: flex
↓ (child must propagate height)
QueryStateBoundary (.ks-query-boundary)
├─ flex: 1
├─ height: 100%
├─ min-height: 0
└─ display: flex
↓ (child must propagate height)
Content Container (grid, splitter, or flex child)
├─ flex: 1 (if flex child)
├─ height: 100% (if direct child of flex parent)
├─ min-height: 0 (always required for flex children)
└─ overflow: (auto|hidden)
↓ (internal scrollable panes)
Internal Panes (.items, .detail-panel, etc.)
├─ flex: 1
├─ min-height: 0
└─ overflow-y: auto
Rationale
- Flex layout principle: Flex children must have
min-height: 0to respect parent constraints - Height inheritance:
height: 100%only works when parent has explicit height - Single responsibility: Each layer only enforces its own constraints, children handle overflow
Implementation
For Grid-Based Pages (.ks-stack)
.ks-stack {
display: grid;
gap: var(--ks-space-4);
flex: 1; /* Required: flex child must expand */
min-height: 0; /* Required: allow internal scroll */
height: 100%; /* Required: inherit parent height */
}
For Master-Detail Pages (KsSplitter)
<KsSplitter storageKey="unique-key" initialRatio="25">
<template #left>
<aside class="request-list">
<h2>Requests</h2>
<div class="items"><!-- flex: 1; min-height: 0; overflow-y: auto; --></div>
</aside>
</template>
<template #right>
<main class="detail-panel">
<!-- height: 100%; min-height: 0; overflow-y: auto; -->
</main>
</template>
</KsSplitter>
Key: KsSplitter pane uses overflow: hidden; each slot's scrollable child must have overflow-y: auto; min-height: 0.
For Flex-Column Containers
.container {
display: flex;
flex-direction: column;
flex: 1; /* Expand to fill parent */
min-height: 0; /* Allow internal overflow */
height: 100%; /* Inherit parent height (optional if flex: 1 works) */
}
.child {
flex: 1; /* Share space with siblings */
min-height: 0; /* Don't prevent scrolling */
overflow-y: auto;/* Internal scroll */
}
Standard CSS Classes (Optional Utilities)
Defined in frontend/src/design-system/base.css:
.ks-flex-column-1 { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.ks-flex-row-1 { display: flex; flex-direction: row; flex: 1; min-height: 0; }
.ks-overflow-auto { overflow-y: auto; }
Note: These are opt-in utilities. Prefer explicit CSS in scoped styles for clarity.
Related Artifacts
-
Commits:
-
Updated Components:
- VersionGovernancePage.vue
- ApprovalQueue.vue (KsSplitter migration)
- ModelOperationsPage.vue
-
Memory: layout_standardization_framework
Verification Checklist
For each new page:
- First load fits viewport (no page scroll)
- Internal panes have
overflow-y: auto; min-height: 0 - Height chain: PageLayout → QueryBoundary → content
- Master-detail uses KsSplitter or equivalent flex layout
- All flex children have
flex: 1; min-height: 0
Future Considerations
- Breakpoints: Responsive layouts (mobile) may need
flex-direction: columnat small widths - Height variants: Consider separate classes for different flex ratios (1:2, 1:1, etc.)
- Template enforcement: CI/CD gate to catch missing height constraints
Questions?
See CLAUDE.md §"Frontend: Vue 3 + Vite + KBX Foundation v4" for component architecture.