
本文介绍一种纯 css 方案,通过 `position: sticky` 结合嵌套容器布局,使左侧导航栏中的顶部和底部区域在页面滚动时始终保持可见,无需 javascript,且能自动适配含固定头部的布局。
在构建现代响应式布局时,常需实现「左侧固定宽度导航栏 + 顶部固定 Header + 右侧主内容可滚动」的三栏结构。但一个典型痛点是:若直接给 .sider 设置 height: 100vh,其内部的“TOP SIDER”和“BOTTOM SIDER”会随视口高度拉伸,无法智能避让顶部 Header;而设为 100% 又因父容器无显式高度而失效。
核心思路:不控制 .sider 的整体高度,而是让其内部关键子元素独立“粘性定位”。CSS 的 position: sticky 允许元素在滚动范围内保持相对位置——top: 0 使其贴顶,bottom: 0 使其贴底,二者共存于同一 flex 容器中,借助 flex-direction: column 和 justify-content: space-between 实现自然分离。
以下是优化后的完整实现:
<!DOCTYPE html>
<html>
<head>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
.header {
background-color: #e74c3c;
color: white;
padding: 16px;
font-weight: bold;
position: sticky;
top: 0;
z-index: 100;
}
.main {
display: flex;
flex-direction: row;
min-height: 100vh;
}
.sider {
width: 220px;
background-color: #3498db;
/* 移除 height: 100vh —— 不再约束外层高度 */
position: sticky;
top: 0;
align-self: flex-start;
/* 确保内部 flex 布局生效 */
display: flex;
flex-direction: column;
height: 100vh; /* 此处保留 100vh 是为了撑起初始高度,但非必需 */
}
.inner-sider {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
padding: 16px 0;
/* 防止 sticky 元素被截断 */
overflow: visible;
}
.inner-top,
.inner-bottom {
padding: 0 16px;
color: white;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 14px;
}
.inner-top {
position: sticky;
top: 0;
background-color: rgba(0,0,0,0.1);
z-index: 10;
}
.inner-bottom {
position: sticky;
bottom: 0;
background-color: rgba(0,0,0,0.1);
z-index: 10;
}
.content {
flex: 1;
background-color: #ecf0f1;
padding: 24px;
overflow-y: auto;
min-height: 100vh;
}
/* 模拟长内容 */
.content::before {
content: "Scroll to see TOP/BOTTOM SIDER stay in place →";
display: block;
color: #7f8c8d;
margin-bottom: 16px;
font-size: 13px;
}
</style>
</head>
<body>
<div class="header">Fixed Header (Sticky)</div>
<div class="main">
<div class="sider">
<div class="inner-sider">
<div class="inner-top">Top Navigation</div>
<div class="inner-bottom">Bottom Tools</div>
</div>
</div>
<div class="content">
<h2>Main Content Area</h2>
<p>This section scrolls independently. Try scrolling up/down — you’ll notice that "Top Navigation" stays pinned just below the header, and "Bottom Tools" remains fixed at the bottom of the viewport — all without JavaScript.</p>
<!-- Long filler -->
<div style="height: 200vh; background: linear-gradient(to bottom, #bdc3c7, #95a5a6); margin-top: 24px;"></div>
<p style="text-align: center; margin-top: 24px; color: #7f8c8d;">End of content</p>
</div>
</div>
</body>
</html>✅ 关键要点说明:
- ✅ .inner-top 和 .inner-bottom 必须同属一个 flex column 容器(.inner-sider),才能通过 justify-content: space-between 分离,并各自触发 sticky 行为;
- ✅ z-index 用于确保 sticky 元素不被其他层遮挡(尤其当 Header 也 sticky 时);
- ✅ .sider 保留 height: 100vh 是为保障初始渲染高度,但即使移除,只要 .inner-sider 有 height: 100% 且父级 .sider 被 flex 布局约束,仍可正常工作;
- ⚠️ 注意:sticky 在 Safari 旧版本或某些嵌套 overflow: hidden 场景下可能失效,建议外层容器避免设置 overflow: hidden 或 transform;
- ? 扩展提示:如需支持多级菜单,可将 .inner-top 替换为
该方案轻量、语义清晰、完全基于 CSS,兼顾可维护性与性能,是构建专业管理后台左侧导航的理想实践之一。










