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

如何实现折叠导航栏先收缩后内容滚动的交互效果?

实现分步收缩导航栏的方案

原生HTML/CSS/JavaScript 实现

核心思路是分两个阶段处理滚动事件:

  1. 第一阶段:滚动距离未超过导航栏「初始高度-最小高度」的差值时,仅收缩导航栏高度,同时同步调整内容的上边距,让内容始终紧贴导航栏底部
  2. 第二阶段:滚动距离超过该差值后,导航栏固定为最小高度,内容正常随滚动向上移动

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>分步收缩导航栏</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .navbar {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            background: #2c3e50;
            color: white;
            transition: height 0.3s ease;
            height: 80px; /* 初始高度 */
            min-height: 40px; /* 最小高度 */
            display: flex;
            align-items: center;
            padding: 0 20px;
        }
        .content {
            padding: 20px;
            margin-top: 80px; /* 初始与导航栏高度匹配 */
            transition: margin-top 0.3s ease;
            background: #ecf0f1;
            min-height: 2000px; /* 保证页面可滚动 */
        }
    </style>
</head>
<body>
    <nav class="navbar">导航栏</nav>
    <div class="content">
        页面内容<br>
        滚动试试效果<br>
        更多内容...
    </div>

    <script>
        const navbar = document.querySelector('.navbar');
        const content = document.querySelector('.content');
        const initialNavHeight = 80;
        const minNavHeight = 40;
        const heightDiff = initialNavHeight - minNavHeight;

        window.addEventListener('scroll', () => {
            const scrollTop = window.scrollY;
            
            if (scrollTop <= heightDiff) {
                // 第一阶段:导航栏收缩,内容同步上移
                const newNavHeight = initialNavHeight - scrollTop;
                navbar.style.height = `${newNavHeight}px`;
                content.style.marginTop = `${newNavHeight}px`;
            } else {
                // 第二阶段:导航栏固定最小高度,内容正常滚动
                navbar.style.height = `${minNavHeight}px`;
                content.style.marginTop = `${minNavHeight}px`;
            }
        });
    </script>
</body>
</html>

关键逻辑说明

  • 计算导航栏高度差值heightDiff作为滚动阶段的阈值
  • 第一阶段通过滚动距离线性调整导航栏高度和内容上边距,确保内容始终紧贴导航栏
  • 第二阶段固定导航栏和内容的间距,让内容随滚动正常上移

React 实现方案

逻辑和原生一致,通过状态管理导航栏高度和内容间距,监听滚动事件更新状态

代码示例

import { useState, useEffect } from 'react';

const App = () => {
    const initialNavHeight = 80;
    const minNavHeight = 40;
    const heightDiff = initialNavHeight - minNavHeight;

    const [navHeight, setNavHeight] = useState(initialNavHeight);
    const [contentMarginTop, setContentMarginTop] = useState(initialNavHeight);

    useEffect(() => {
        const handleScroll = () => {
            const scrollTop = window.scrollY;
            if (scrollTop <= heightDiff) {
                const newHeight = initialNavHeight - scrollTop;
                setNavHeight(newHeight);
                setContentMarginTop(newHeight);
            } else {
                setNavHeight(minNavHeight);
                setContentMarginTop(minNavHeight);
            }
        };

        window.addEventListener('scroll', handleScroll);
        return () => window.removeEventListener('scroll', handleScroll);
    }, []);

    return (
        <div className="app">
            <nav 
                style={{
                    position: 'fixed',
                    top: 0,
                    left: 0,
                    width: '100%',
                    backgroundColor: '#2c3e50',
                    color: 'white',
                    transition: 'height 0.3s ease',
                    height: `${navHeight}px`,
                    display: 'flex',
                    alignItems: 'center',
                    padding: '0 20px'
                }}
            >
                导航栏
            </nav>
            <div 
                style={{
                    padding: '20px',
                    marginTop: `${contentMarginTop}px`,
                    transition: 'margin-top 0.3s ease',
                    backgroundColor: '#ecf0f1',
                    minHeight: '2000px'
                }}
            >
                页面内容<br />
                滚动试试效果<br />
                更多内容...
            </div>
        </div>
    );
};

export default App;

关键逻辑说明

  • 用useState维护导航栏高度和内容间距的状态
  • 在useEffect中绑定滚动监听,分阶段更新状态
  • 组件卸载时移除监听,避免内存泄漏

这个方案完全可行,能精准实现你要求的分步滚动效果:先收缩导航栏,内容始终贴紧;导航栏到达最小高度后,内容再往上滑入导航栏下方。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:11:11