如何用CSS实现菜单文本随滑动背景动态切换指定颜色的效果?
解决方案:用mix-blend-mode: difference结合颜色适配实现
我们可以通过调整文本与滑动背景的颜色组合,利用混合模式实现「仅被背景覆盖的文本变色」的需求,同时保留平滑滑动动画。以下是完整实现:
HTML
<nav class="tabs"> <div class="tab-slider"></div> <ul> <li class="active"><a href="#">关于</a></li> <li><a href="#">概述</a></li> <li><a href="#">参考</a></li> <li><a href="#">日志</a></li> <li><a href="#">目录</a></li> <li><a href="#">提交</a></li> <li><a href="#">对比</a></li> <li><a href="#">统计</a></li> </ul> </nav>
CSS
html { font-family: sans-serif; background-color: #fff; /* 页面基础背景色 */ } .tabs { position: relative; /* 让滑动背景相对容器定位 */ } .tabs ul { display: flex; list-style: none; padding: 0; margin: 0; } .tabs li { padding: 8px 16px; cursor: pointer; } .tabs a { text-decoration: none; color: #fff; /* 文本基础色设为白色 */ mix-blend-mode: difference; /* 开启颜色混合模式 */ } .tab-slider { position: absolute; background-color: #007bff; /* 滑动背景色(蓝色示例) */ z-index: -1; /* 放在文本下方 */ transition: all 0.3s ease; /* 平滑滑动动画 */ border-radius: 4px; /* 可选:添加圆角优化视觉 */ }
JavaScript
const slider = document.querySelector('.tab-slider'); // 绑定菜单项点击事件 document.querySelectorAll('.tabs li').forEach(li => { li.addEventListener('click', () => { // 移除旧的活跃状态 document.querySelector('.active')?.classList.remove('active'); // 标记当前项为活跃 li.classList.add('active'); // 更新滑动背景的位置与尺寸 slider.style.left = `${li.offsetLeft}px`; slider.style.width = `${li.offsetWidth}px`; slider.style.height = `${li.offsetHeight}px`; }); }); // 初始化滑动背景位置 const initActiveLi = document.querySelector('.active'); slider.style.left = `${initActiveLi.offsetLeft}px`; slider.style.width = `${initActiveLi.offsetWidth}px`; slider.style.height = `${initActiveLi.offsetHeight}px`;
原理说明
- 非活跃状态:白色文本与页面白色背景通过
difference模式混合,最终显示为黑色(符合非活跃文本颜色要求)。 - 活跃状态:白色文本与蓝色滑动背景通过
difference模式混合,视觉上呈现白色(满足活跃文本颜色需求)。 - 滑动动画:通过JS动态修改滑动背景的
left、width属性,结合CSS过渡实现平滑的位置切换效果。
精准纯白文本的替代方案
如果需要严格的纯白文本(而非混合近似色),可以采用双层文本+遮罩的方式:
- 每个菜单项包含两层文本:一层黑色(非活跃)、一层白色(活跃)。
- 通过滑动背景同步控制白色文本的显示范围。
关键代码示例:
.tabs li { position: relative; } .tabs li span { display: block; } .tabs li .active-text { position: absolute; top: 0; left: 0; color: #fff; clip-path: inset(0 100% 0 0); /* 初始隐藏白色文本 */ transition: clip-path 0.3s ease; } .tabs li.active .active-text { clip-path: inset(0 0 0 0); /* 显示白色文本 */ }
该方案需调整HTML结构(将<a>替换为两个<span>),视觉效果更精准,但代码复杂度略高。
内容的提问来源于stack exchange,提问作者user8649828
相关产品推荐
相关产品推荐

