如何用CSS实现随头部可见性自适应高度的左侧导航菜单?
问题
我正在构建一个包含顶部滚动Header、左侧Sider菜单和右侧滚动Content的基础布局,右侧Content随主滚动条滚动。需求如下:
- 左侧Sider中的"TOP SIDER"和"BOTTOM SIDER"始终显示在视口中
- Sider高度需随Header是否可见动态调整
已知用JS可实现该效果,想了解是否可用纯CSS实现,已耗费数小时仍未解决。
原始示例代码
<html> <head> <style> body { margin: 0; padding: 0; } .header { background-color: red; } .main { background-color: green; display: flex; flex-direction: row; } .sider { width: 200px; background-color: cornflowerblue; height: 100vh; /* I think here is the problem */ position: sticky; top:0; align-self: flex-start; } .inner-sider { height: 100%; display: flex; flex-direction: column; justify-content: space-between; } </style> </head> <body> <div class="header">Header</div> <div class="main"> <div class="sider"> <div class="inner-sider"> <div>TOP SIDER</div> <div>BOTTOM SIDER</div> </div> </div> <div class="content"> MAIN CONTENT <!-- SIMULATE A LAGE CONTENT PAGE--> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br> END OF MAIN CONTENT </div> </div> </body> </html>
补充说明:示例中的两个内层<div>仅用于展示Inner Sider的顶部和底部区域,实际场景中Inner Sider应为全屏高度菜单。
纯CSS实现方案
可以通过CSS滚动驱动动画结合动态计算属性实现,无需JavaScript。以下是优化后的代码及关键说明:
修改后的完整代码
<html> <head> <style> body { margin: 0; padding: 0; overflow-x: hidden; } .header { background-color: red; padding: 1rem; /* 固定Header高度用于计算;若需动态高度,可结合JS同步变量,纯CSS建议固定或用min-height */ min-height: 52px; box-sizing: border-box; } .main { background-color: green; display: flex; flex-direction: row; min-height: calc(100vh - 52px); } .sider { width: 200px; background-color: cornflowerblue; position: sticky; top: 0; align-self: flex-start; /* 动态计算Sider高度:Header可见时减去Header高度,不可见时占满视口 */ height: calc(100vh - max(0px, 52px - var(--scroll-top))); } .inner-sider { height: 100%; display: flex; flex-direction: column; justify-content: space-between; padding: 1rem; box-sizing: border-box; } /* 通过滚动驱动动画更新滚动距离变量 */ @keyframes track-scroll { to { --scroll-top: 100vh; } } body { animation: track-scroll linear; animation-timeline: scroll(root); animation-range: 0 100vh; } </style> </head> <body> <div class="header">Header</div> <div class="main"> <div class="sider"> <div class="inner-sider"> <div>TOP SIDER</div> <div>BOTTOM SIDER</div> </div> </div> <div class="content"> MAIN CONTENT <!-- SIMULATE A LAGE CONTENT PAGE--> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br> END OF MAIN CONTENT </div> </div> </body> </html>
核心实现逻辑
- 滚动距离追踪:利用CSS滚动驱动动画
animation-timeline: scroll(root),将页面滚动距离同步到--scroll-top变量。 - 动态高度计算:
- 当Header在视口中(滚动距离 < Header高度),
52px - var(--scroll-top)为正数,Sider高度 = 视口高度 - Header高度,确保底部内容不被Header遮挡。 - 当Header滚出视口(滚动距离 ≥ Header高度),
52px - var(--scroll-top)为负数,max(0px, ...)取0,Sider高度自动变为100vh,占满整个视口。
- 当Header在视口中(滚动距离 < Header高度),
- Sticky定位:Sider设置
position: sticky; top: 0,确保其始终固定在视口左侧,不会随Content滚动移出视野。
兼容性说明
CSS滚动驱动动画目前已在Chrome、Edge等现代浏览器支持,若需兼容旧版浏览器,可改用position: fixed配合降级方案,但纯CSS下无法完美适配动态Header高度的场景,此时建议结合少量JavaScript同步Header高度变量。
内容的提问来源于stack exchange,提问作者LWlook
相关产品推荐
相关产品推荐

