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

window.scrollTo与position fixed菜单滚动异常问题求助

问题分析与解决方案:fixed菜单滚动后链接跳转异常

你的问题出在两个关键地方:

  1. 没有阻止a标签的默认跳转行为,点击带href="#"的链接会直接跳转到页面顶部
  2. 滚动目标位置的计算逻辑错误,用了视口相对位置而非文档相对位置

具体原因

  • article.getBoundingClientRect().top返回的是元素相对于当前视口的顶部距离,而window.scrollTo的top参数需要的是相对于文档顶部的绝对距离。当页面已经滚动过一段距离后,这个视口相对值会和当前滚动位置叠加,导致计算出的目标位置完全错误。
  • 同时,a标签的默认跳转行为(跳转到#对应的锚点,也就是页面顶部)会在你的自定义平滑滚动之后触发,直接覆盖掉你的预期效果。

修复步骤

  • 阻止默认行为:在链接的click事件处理函数开头添加e.preventDefault();,取消a标签的默认跳转逻辑
  • 修正位置计算:用article.offsetTop获取元素到文档顶部的绝对距离,再减去菜单的高度(避免fixed菜单挡住元素内容)

修改后的代码

JavaScript

const arr = ['home', 'about', 'services', 'tours'];
const containerArticles = document.querySelector('.container-articles');
const containerNav = document.querySelector('.nav');
const links = document.querySelectorAll('.nav-links > li > a');

const getArticles = arr.map(item => {
    return `    <article data-id=${item}>
    <h1>${item}</h1>
</article>
`;
});

containerArticles.innerHTML = getArticles.join('');


// 处理菜单链接点击事件
for (let link of links) {
    link.addEventListener('click', e => {
        // 阻止a标签默认跳转
        e.preventDefault();
        const targetText = e.target.textContent.trim();

        for (let article of document.querySelectorAll('article')) {
            if (targetText === article.dataset.id) {
                // 计算目标位置:元素到文档顶部距离 - 菜单高度
                window.scrollTo({
                    top: article.offsetTop - containerNav.offsetHeight,
                    left: 0,
                    behavior: 'smooth'
                });
            }
        }
    });
}

// 滚动时切换菜单样式
window.addEventListener('scroll', () => {
    if (pageYOffset > containerNav.offsetHeight) {
        containerNav.classList.add('nav-sticky');
    } else {
        containerNav.classList.remove('nav-sticky');
    }
});

CSS(无需修改)

*,::after,::before {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

header {
    position: relative;
    min-height: 100vh;
    background-color: antiquewhite;
    background: url('img/mountain.jpeg') center/cover no-repeat;
    display: flex;
    flex-wrap: wrap;
    align-items: start;
    justify-content: center;
}

header::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    background-color: rgba(8, 126, 88, 0.5);
}

.nav {
    position: fixed;
    top: 0;
    width: 100%;
    height: 50px;
    background-color: aliceblue;
    display: flex;
    justify-content: end;
    align-items: center;
    padding: 1rem;
    transition: 0.4s;
    z-index: 999;

}

.nav-sticky {
    height: 60px;
    background-color: white;
    justify-content: center;
}

.nav ul {
    list-style-type: none;
}

.nav ul li {
    display: inline-block;
    padding-left: 1rem;
    padding-right: 1rem;
}

.header-container {
    align-self: center;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 50%;
    z-index: 1;
}

.header-title,.header-desc {
    text-align: center;
    color: white;
}

.header-title {
    margin-bottom: 1rem;
}

.header-desc {
    margin-top: 1rem;
    margin-bottom: 1rem;
    letter-spacing: 1px;
    line-height: 20px;
}

.btn-explore {
    margin-top: 1rem;
    width: 110px;
    height: 40px;
    border: 1px solid white;
    background-color: transparent;
    color: white;
    font-weight: 900;
    border-radius: 10px;
    cursor: pointer;
}

article {
    min-height: 90vh;
    background-color: aliceblue;
}

article h1 {
    text-align: center;
    text-transform: uppercase;
}

HTML(无需修改)

<body>
<header>
    <nav class="nav">
        <ul class="nav-links">
            <li><a href="#">home</a></li>
            <li><a href="#">about</a></li>
            <li><a href="#">services</a></li>
            <li><a href="#">tours</a></li>
        </ul>
    </nav>
    <div class="header-container">
        <h1 class="header-title">Scroll Project</h1>
        <p class="header-desc">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Vero sed tempore ipsam distinctio delectus doloribus excepturi quidem eum ratione doloremque.</p>
        <button class="btn-explore">Explore Tours</button>
    </div>
</header>
<section class="container-articles">
    <article>
        <h1></h1>
    </article>
</section>
</body>

额外优化说明

  • 给target.textContent添加了trim(),避免文本前后空格导致匹配失败
  • 如果页面滚动频繁,可给滚动事件添加节流处理,减少性能消耗(当前代码量小,暂不影响)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:57:15