You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在高度不固定的sticky header下方实现固定菜单?

实现高度不固定的Sticky Header下方固定菜单

你当前的实现依赖header .top的固定高度来设置菜单偏移,但当header高度动态变化(比如banner内容调整、响应式布局)时,固定值会失效。下面提供两种可行的适配方案:

方案一:JS+CSS动态计算(无需调整HTML结构)

通过JS实时获取header的高度,动态设置菜单的位置和高度,同时监听可能导致header高度变化的事件,确保布局始终正确。

修改后的代码

HTML(结构不变)

<body>
  <div id="root">
    <header>
      <div class="top">
        Header
        <button type="button">Open</button>
      </div>
      <div class="banner">
        Banner <!-- 内容可动态修改,header高度自动适配 -->
      </div>
      <nav>Menu
        <ul>
          <li>A</li>
          <li>B</li>
          <li>C</li>
          <li>D</li>
        </ul>
      </nav>
    </header>
    <main>
      <div>
        <p></p>
        <ul>
          <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</li>
          <li>Duis id sem non risus blandit convallis in ac ipsum.</li>
          <li>Mauris iaculis nisi at tellus aliquet vestibulum.</li>
        </ul>
        <p></p>
        <p></p>
        <ul>
          <li>Aenean varius nulla sit amet ex aliquam porttitor.</li>
          <li>Fusce ut sapien ut diam elementum elementum.</li>
          <li>Maecenas vehicula dui a consectetur tempor.</li>
        </ul>
        <p></p>
        <p></p>
        <ul>
          <li>Morbi nec ante efficitur, malesuada lectus nec, accumsan massa.</li>
          <li>Donec vitae arcu sed nunc tristique cursus id et turpis.</li>
          <li>Ut mattis ante dictum congue egestas.</li>
          <li>Ut a odio gravida, faucibus erat id, fermentum felis.</li>
          <li>Suspendisse vitae libero feugiat, iaculis augue et, vestibulum ex.</li>
        </ul>
        <p></p>
        <p></p>
        <ul>
          <li>Proin eleifend velit sit amet gravida tempor.</li>
        </ul>
        <p></p>
        <p></p>
        <ul>
          <li>Nam ut tortor ut leo posuere pharetra quis efficitur nisl.</li>
          <li>Suspendisse efficitur elit in lacus mollis, eu facilisis orci vulputate.</li>
          <li>Donec vulputate purus ut ligula euismod, eu venenatis tellus commodo.</li>
          <li>Praesent semper dui nec mattis lacinia.</li>
          <li>Duis dignissim justo quis rhoncus maximus.</li>
        </ul>
        <p></p>
      </div>
    </main>
  </div>
</body>

CSS

#root {
  height: 200px;
  overflow-y: scroll;
  scrollbar-gutter: stable;
  position: relative; /* 让菜单绝对定位相对于root容器 */
}

#root.hide-overflow {
  overflow-y: hidden;
}

header {
  position: sticky;
  top: 0;
  background: orange;
  z-index: 2; /* 确保header在菜单上方 */
}

.banner {
  background: cyan;
}

nav {
  display: none;
  overscroll-behavior: contain;
  position: absolute;
  right: 0;
  width: 50%;
  background: green;
  z-index: 1;
}

nav.open {
  display: block;
}

JavaScript

const root = document.getElementById('root');
const button = document.querySelector('button');
const nav = document.querySelector('nav');
const header = document.querySelector('header');

let open = false;

// 计算并更新菜单的位置和高度
function updateMenuLayout() {
  if (!open) return;
  const headerHeight = header.offsetHeight;
  const rootHeight = root.offsetHeight;
  nav.style.top = `${headerHeight}px`;
  nav.style.height = `${rootHeight - headerHeight}px`;
}

// 切换菜单显示/隐藏
function toggleMenu() {
  open = !open;
  if (open) {
    button.innerText = 'Close';
    nav.classList.add('open');
    root.classList.add('hide-overflow');
    updateMenuLayout(); // 打开时立即计算布局
  } else {
    button.innerText = 'Open';
    nav.classList.remove('open');
    root.classList.remove('hide-overflow');
  }
}

// 监听窗口大小变化和header内容更新
window.addEventListener('resize', updateMenuLayout);
const headerObserver = new MutationObserver(updateMenuLayout);
headerObserver.observe(header, {
  childList: true,
  subtree: true,
  attributes: true
});

button.addEventListener('click', toggleMenu);

方案二:调整HTML结构+CSS Grid(简化逻辑)

如果允许调整HTML结构,将菜单移到root容器内(与header同级),可以用Grid布局配合CSS变量,减少JS代码量。

修改后的代码

HTML

<body>
  <div id="root">
    <header>
      <div class="top">
        Header
        <button type="button">Open</button>
      </div>
      <div class="banner">
        Banner
      </div>
    </header>
    <!-- 将nav移到root下,与header、main同级 -->
    <nav>Menu
      <ul>
        <li>A</li>
        <li>B</li>
        <li>C</li>
        <li>D</li>
      </ul>
    </nav>
    <main>
      <!-- 内容不变 -->
    </main>
  </div>
</body>

CSS

#root {
  height: 200px;
  overflow-y: scroll;
  scrollbar-gutter: stable;
  display: grid;
  grid-template-rows: auto 1fr; /* header高度自适应,main占剩余空间 */
  position: relative;
}

header {
  position: sticky;
  top: 0;
  background: orange;
  z-index: 2;
}

.banner {
  background: cyan;
}

nav {
  display: none;
  overscroll-behavior: contain;
  position: absolute;
  right: 0;
  top: 0;
  height: 100%;
  width: 50%;
  background: green;
  z-index: 1;
  margin-top: var(--header-height); /* 通过JS设置header高度的CSS变量 */
}

nav.open {
  display: block;
}

JavaScript

const root = document.getElementById('root');
const button = document.querySelector('button');
const nav = document.querySelector('nav');
const header = document.querySelector('header');

let open = false;

// 更新header高度的CSS变量
function updateHeaderHeight() {
  document.documentElement.style.setProperty('--header-height', `${header.offsetHeight}px`);
}

// 切换菜单显示/隐藏
function toggleMenu() {
  open = !open;
  if (open) {
    button.innerText = 'Close';
    nav.classList.add('open');
    root.classList.add('hide-overflow');
    updateHeaderHeight();
  } else {
    button.innerText = 'Open';
    nav.classList.remove('open');
    root.classList.remove('hide-overflow');
  }
}

// 监听窗口大小变化和header内容更新
window.addEventListener('resize', updateHeaderHeight);
const headerObserver = new MutationObserver(updateHeaderHeight);
headerObserver.observe(header, {
  childList: true,
  subtree: true,
  attributes: true
});

button.addEventListener('click', toggleMenu);

两种方案均能适配header高度不固定的场景:方案一无需修改HTML结构,兼容性更强;方案二结构更清晰,CSS逻辑更简洁,可根据实际需求选择。

内容的提问来源于stack exchange,提问作者steinybot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 11:10:35