基于HTML、CSS和JavaScript实现任天堂Wii菜单缩放过渡动画
实现任天堂Wii菜单频道点击过渡动画方案
核心逻辑拆解
原版动画的关键不是放大频道组件,而是通过视口聚焦过渡营造镜头推进的错觉:点击频道时,一个与频道完全匹配的“窗口”从当前位置平滑放大至全屏,同时内部内容切换为频道页面,频道本身全程保持原尺寸无变形。
原生实现步骤(HTML/CSS/JS)
1. 基础布局结构
<!-- 主菜单容器 --> <div class="wii-menu"> <div class="channel" data-channel="1">频道1</div> <div class="channel" data-channel="2">频道2</div> <!-- 更多频道 --> </div> <!-- 过渡遮罩层 --> <div class="transition-overlay"> <div class="overlay-content"> <!-- 频道内容容器,默认隐藏 --> <div class="channel-content" id="content-1">频道1内容</div> <div class="channel-content" id="content-2">频道2内容</div> </div> </div>
2. CSS样式与动画
.wii-menu { position: relative; width: 100vw; height: 100vh; background: #000; } .channel { position: absolute; width: 180px; height: 240px; background: #333; color: #fff; /* 频道定位,示例值 */ top: 100px; left: 200px; cursor: pointer; } .transition-overlay { position: fixed; top: 0; left: 0; width: 0; height: 0; overflow: hidden; z-index: 999; background: #000; /* 初始隐藏 */ opacity: 0; } .channel-content { display: none; width: 100vw; height: 100vh; color: #fff; } /* 放大动画关键帧 */ @keyframes zoomToFull { from { /* 初始尺寸和位置由JS动态设置 */ } to { width: 100vw; height: 100vh; top: 0; left: 0; opacity: 1; } } .overlay-active { animation: zoomToFull 350ms ease-out forwards; }
3. JS触发与控制
const channels = document.querySelectorAll('.channel'); const overlay = document.querySelector('.transition-overlay'); const contents = document.querySelectorAll('.channel-content'); channels.forEach(channel => { channel.addEventListener('click', () => { const rect = channel.getBoundingClientRect(); // 设置遮罩层初始位置和尺寸 overlay.style.width = `${rect.width}px`; overlay.style.height = `${rect.height}px`; overlay.style.top = `${rect.top}px`; overlay.style.left = `${rect.left}px`; overlay.style.opacity = '1'; // 显示对应频道内容 const channelId = channel.dataset.channel; contents.forEach(c => c.style.display = 'none'); document.getElementById(`content-${channelId}`).style.display = 'block'; // 触发动画 overlay.classList.add('overlay-active'); // 动画结束后隐藏菜单 overlay.addEventListener('animationend', () => { document.querySelector('.wii-menu').style.display = 'none'; }, { once: true }); }); }); // 返回菜单逻辑(示例:点击内容区域返回) contents.forEach(content => { content.addEventListener('click', () => { document.querySelector('.wii-menu').style.display = 'block'; overlay.classList.remove('overlay-active'); // 重置遮罩层状态 setTimeout(() => { overlay.style.width = '0'; overlay.style.height = '0'; overlay.style.opacity = '0'; }, 350); }); });
优化要点
- 确保遮罩层初始的背景图与频道缩略图完全一致,避免视觉断层。
- 使用
getBoundingClientRect()获取精准的频道位置,避免偏移。 - 动画时长设为300-400ms,匹配原版Wii的过渡节奏。
- 可添加背景变暗的同步动画,增强沉浸感。
工具简化方案
如果不想手动计算参数,可使用GSAP动画库的fromTo方法,快速实现精准的尺寸和位置过渡,减少代码量。
内容的提问来源于stack exchange,提问作者tobieche
相关产品推荐
相关产品推荐

