基于背景色动态切换导航栏(Logo及菜单)颜色的实现方案
实现导航Logo与菜单颜色随横向滚动平滑切换
实现思路
- 给每个滚动区块配置对应的导航目标颜色,通过自定义属性存储
- 监听Locomotive Scroll的滚动事件,获取横向滚动位置与进度
- 基于滚动进度对相邻区块的目标颜色进行插值计算,实现平滑过渡
- 将计算后的颜色应用到Logo和菜单元素上
代码修改与实现
1. HTML结构调整
给每个区块添加data-nav-color属性定义导航目标颜色,同时给导航元素添加ID方便选择:
<nav class="fixed w-full z-50" id="main-nav"> <div class="container mx-auto flex my-7"> <div class="w-1/2" id="logo-container"> <!-- 建议使用可修改fill的SVG格式Logo,若为PNG需调整方案 --> <img src="/logo.svg" alt="logo" /> </div> <ul class="flex w-1/2 gap-7 justify-end items-center text-white font-spacegrotesk" id="menu-list"> <li>Work</li> <li>About</li> <li>Contact</li> </ul> </div> </nav> <div class="scroll-container relative w-full flex"> <div data-scroll-section class="min-w-full min-h-screen h-screen bg-[#EDE1D1]" data-nav-color="#ffffff"> <h1 class="text-white">section 1</h1> </div> <div data-scroll-section class="min-w-full min-h-screen h-screen bg-[#BD7E36]" data-nav-color="#ff0000"> <h1 class="text-green-700">section 2</h1> </div> <div data-scroll-section class="min-w-full min-h-screen h-screen bg-[#6F311A]" data-nav-color="#00ff00"> <h1 class="text-black">section 3</h1> </div> </div>
2. JavaScript逻辑实现
添加颜色转换、插值计算与滚动监听逻辑:
// 十六进制颜色转RGB数组 function hexToRgb(hex) { const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b); const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? [ parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16) ] : null; } // 颜色插值计算(实现平滑过渡) function interpolateColor(color1, color2, factor) { const result = []; for (let i = 0; i < 3; i++) { result[i] = Math.round(color1[i] + factor * (color2[i] - color1[i])); } return `rgb(${result.join(',')})`; } // 初始化Locomotive Scroll var locoScroll = new LocomotiveScroll({ el: document.querySelector('.scroll-container'), smooth: true, direction: 'horizontal', class: true, multiplier: 1, lerp: 0.04, scrollbarContainer: false, getDirection: true, getSpeed: true, scrollFromAnywhere: true, }); // 获取DOM元素 const logoImg = document.querySelector('#logo-container img'); const menuItems = document.querySelectorAll('#menu-list li'); const sections = document.querySelectorAll('[data-scroll-section]'); const sectionColors = Array.from(sections).map(section => hexToRgb(section.dataset.navColor)); let sectionWidth = window.innerWidth; // 初始设置导航颜色 function setInitialColor() { const initialColor = sectionColors[0]; const initialRgb = `rgb(${initialColor.join(',')})`; menuItems.forEach(item => item.style.color = initialRgb); logoImg.style.fill = initialRgb; } // 窗口大小变化时更新区块宽度 window.addEventListener('resize', () => { sectionWidth = window.innerWidth; }); // 页面加载完成后设置初始颜色 window.addEventListener('load', setInitialColor); // 监听滚动事件更新导航颜色 locoScroll.on('scroll', (args) => { const scrollX = args.scroll.x; const currentSectionIndex = Math.floor(scrollX / sectionWidth); const nextSectionIndex = Math.min(currentSectionIndex + 1, sections.length - 1); const progress = (scrollX % sectionWidth) / sectionWidth; const currentColor = sectionColors[currentSectionIndex]; const nextColor = sectionColors[nextSectionIndex]; const targetColor = interpolateColor(currentColor, nextColor, progress); // 应用颜色到菜单和Logo menuItems.forEach(item => item.style.color = targetColor); logoImg.style.fill = targetColor; });
注意事项
- 若你的Logo是PNG格式,无法直接通过
fill属性修改颜色,建议替换为SVG格式;或使用CSS滤镜(如filter: hue-rotate())实现颜色变化,但自定义精准颜色的话SVG方案更可靠。 - 可根据需求调整
interpolateColor函数中的计算逻辑,优化过渡效果。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

