仅在垂直内容溢出时启用Sticky导航栏的问题与解决方案
WhatsApp风格导航栏滚动条自适应解决方案
问题场景
开发WhatsApp风格导航栏时,sticky导航功能正常,但存在一个问题:即使内容较少的页面,浏览器滚动条仍会显示。原因是内容容器的高度由内部最长的section(比如示例里的PAGE 5)决定,导致所有页面都强制出现滚动条。需求是:
- 短内容页面:隐藏滚动条,不启用滚动逻辑
- 长内容页面:显示滚动条,保留sticky导航功能
解决方案思路
通过CSS调整基础布局,配合JavaScript动态判断内容高度来控制滚动状态:
- CSS调整:设置body初始
overflow: hidden,section使用min-content和min-height适配内容高度,避免容器被最长section拉伸 - JavaScript逻辑:监听导航项点击事件,判断当前激活section的高度,动态设置body的
overflowY属性
原问题代码
JavaScript
let navItems = document.querySelectorAll(".nav-item"); // 添加CSS变量记录导航项数量 document.body.style.setProperty("--total-nav-items", `${navItems.length}`); navItems.forEach((item, index) => { item.addEventListener("click", () => { // 修改CSS变量控制导航指示器位置 document.body.style.setProperty("--index", `${index}`); toogleActive(); function toogleActive() { // 移除所有导航项的active类 navItems.forEach((itemWithClass) => { itemWithClass.classList.remove("active"); }); // 给当前点击的导航项添加active类 item.classList.add("active"); } }); });
CSS
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500&display=swap"); :root { --nav-height: 3rem; --nav-bg: rgb(0, 128, 105); --text-color: white; --anim-speed: 0.5s; color-scheme: light dark; } * { box-sizing: border-box; } body { margin: 0; overflow-y: auto; overflow-x: hidden; } header { background-color: var(--nav-bg); height: var(--nav-height); display: grid; place-items: center start; } nav { display: flex; height: var(--nav-height); background-color: var(--nav-bg); color: var(--text-color); text-transform: uppercase; font-family: poppins; user-select: none; position: sticky; top: 0; width: 100vw; } nav .nav-item { flex: 1; display: grid; place-items: center; opacity: 0.5; transition: opacity var(--anim-speed); } nav .nav-item:active { background-color: rgba(255, 255, 255, 0.2); } nav .nav-item.active { opacity: 1; } nav::before { --indicator-width: calc(100% / var(--total-nav-items)); content: ""; position: absolute; height: 0.2rem; width: var(--indicator-width); background-color: var(--text-color); bottom: 0; left: calc(var(--index, 0) * var(--indicator-width)); transition: left var(--anim-speed); box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.5); } #container { position: relative; z-index: -1; left: calc(-1 * (var(--index, 0) * 100vw)); transition: left var(--anim-speed); display: grid; grid-auto-flow: column; grid-auto-columns: 100vw; } #container>* { height: calc(100vh - var(--nav-height)); padding: 0 1rem; } @media (prefers-color-scheme: dark) { :root { --nav-bg: rgb(31, 44, 52); --text-color: rgb(9, 148, 115); } }
修复后代码
JavaScript
let navItems = document.querySelectorAll(".nav-item"); let sections = document.querySelectorAll("#container > *"); // 添加CSS变量记录导航项数量 document.body.style.setProperty("--total-nav-items", `${navItems.length}`); navItems.forEach((item, index) => { item.addEventListener("click", () => { // 修改CSS变量控制导航指示器位置 document.body.style.setProperty("--index", `${index}`); toogleActive(); disactivateScroll(); function toogleActive() { // 移除所有导航项的active类 navItems.forEach((itemWithClass) => { itemWithClass.classList.remove("active"); }); // 给当前点击的导航项添加active类 item.classList.add("active"); } function disactivateScroll() { let navHeight = document.querySelector("nav").offsetHeight; // 计算页面最小可用高度(减去导航栏的两倍高度) let minHeightSection = window.innerHeight - (navHeight * 2); // 判断当前section高度是否超过最小可用高度,动态设置滚动状态 if (sections[index].offsetHeight > minHeightSection) { document.body.style.overflowY = "auto"; } else { document.body.style.overflowY = "hidden"; } } }); });
CSS
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500&display=swap"); :root { --nav-height: 3rem; --nav-bg: rgb(0, 128, 105); --text-color: white; --anim-speed: 0.5s; color-scheme: light dark; } * { box-sizing: border-box; } body { margin: 0; overflow: hidden; } header { background-color: var(--nav-bg); height: var(--nav-height); display: grid; place-items: center start; } nav { display: flex; height: var(--nav-height); background-color: var(--nav-bg); color: var(--text-color); text-transform: uppercase; font-family: poppins; user-select: none; position: sticky; top: 0; width: 100vw; } nav .nav-item { flex: 1; display: grid; place-items: center; opacity: 0.5; transition: opacity var(--anim-speed); } nav .nav-item:active { background-color: rgba(255, 255, 255, 0.2); } nav .nav-item.active { opacity: 1; } nav::before { --indicator-width: calc(100% / var(--total-nav-items)); content: ""; position: absolute; height: 0.2rem; width: var(--indicator-width); background-color: var(--text-color); bottom: 0; left: calc(var(--index, 0) * var(--indicator-width)); transition: left var(--anim-speed); box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.5); } #container { position: relative; z-index: -1; left: calc(-1 * (var(--index, 0) * 100vw)); transition: left var(--anim-speed); display: grid; grid-auto-flow: column; grid-auto-columns: 100vw; } #container>* { height: min-content; min-height: calc(100vh - (var(--nav-height) * 2)); padding: 0 1rem; border: 5px solid red; } @media (prefers-color-scheme: dark) { :root { --nav-bg: rgb(31, 44, 52); --text-color: rgb(9, 148, 115); } }
内容的提问来源于stack exchange,提问作者user19485937
相关产品推荐
相关产品推荐

