
本文介绍如何通过叠加双层文本与 CSS clip 或宽度裁剪技术,实现鼠标移动时在指定区域(如标题)上实时“划过”并切换前后文字颜色的效果,兼顾性能与视觉准确性。
本文介绍如何通过叠加双层文本与 css `clip` 或宽度裁剪技术,实现鼠标移动时在指定区域(如标题)上实时“划过”并切换前后文字颜色的效果,兼顾性能与视觉准确性。
在前端交互动效中,常需实现“鼠标划过文字,左侧变白、右侧保持原色”的渐进式视觉反馈。原始方案尝试通过计算鼠标相对于
的横向位置,并动态设置 RGB 值进行插值着色,但存在明显局限:纯色文字无法真正实现“分段着色”——因为 是一个整体 DOM 元素,CSS color 属性作用于全部字符,无法按像素位置精确切割单个字母的显示颜色。
更高效、语义清晰且兼容性良好的解法是:采用双层文本叠加 + 精确裁剪(clipping)。核心思路如下:
- 创建两个完全重叠的
元素:底层为原始样式(如深色背景上的黑色文字),顶层为高对比色(如白色文字);
- 通过绝对定位使二者严格对齐;
- 利用 clip: rect(top, right, bottom, left) 或现代 clip-path 动态裁剪顶层元素的显示区域;
- 鼠标移动时,仅更新顶层的裁剪右边界(right 值),使其从左向右逐步显露,从而形成“白色文字随鼠标推进”的视觉效果。
✅ 推荐使用 clip-path(现代标准,更直观)或回退方案 clip(兼容 IE9+)。以下为完整可运行示例(含防抖与边界保护):
<div id="box-wrapper">
<div class="box base">
<h1>The power of Gods</h1>
</div>
<div class="box reveal" id="box-reveal">
<h1>The power of Gods</h1>
</div>
</div>
#box-wrapper {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.box {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Verdana', 'Geneva', 'Tahoma', sans-serif;
font-weight: bold;
font-size: 4rem;
line-height: 1;
white-space: nowrap;
}
.base {
background-color: #F84F39;
color: #000;
}
.reveal {
background-color: #1B1A27;
color: #FFF;
/* 使用 clip-path 实现平滑裁剪(推荐) */
clip-path: inset(0 100% 0 0); /* 初始:完全隐藏 */
/* 回退方案(旧浏览器): */
/* clip: rect(0, 0, 9999px, 0); */
}
const wrapper = document.getElementById('box-wrapper');
const revealBox = document.getElementById('box-reveal');
wrapper.addEventListener('mousemove', (e) => {
const rect = wrapper.getBoundingClientRect();
const x = e.clientX - rect.left;
const width = Math.max(0, Math.min(x, rect.width));
// 使用 clip-path(现代浏览器)
revealBox.style.clipPath = `inset(0 ${100 - (width / rect.width * 100)}% 0 0)`;
// 若需兼容旧版 Chrome/Safari,启用以下回退(注意单位必须为 px):
// revealBox.style.clip = `rect(0, ${width}px, ${rect.height}px, 0)`;
});
// 可选:添加 touch 支持(移动端)
wrapper.addEventListener('touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
const rect = wrapper.getBoundingClientRect();
const x = touch.clientX - rect.left;
const width = Math.max(0, Math.min(x, rect.width));
revealBox.style.clipPath = `inset(0 ${100 - (width / rect.width * 100)}% 0 0)`;
});
⚠️ 注意事项与优化建议:
- 避免布局抖动:确保 .box 使用 white-space: nowrap 和固定 font-size/line-height,防止文字换行导致 getBoundingClientRect() 计算偏移;
- 性能优先:clip-path 在现代浏览器中硬件加速良好;若需极致性能,可用 transform: scaleX() 配合 overflow: hidden 替代,但会拉伸文字;
- 响应式适配:在 resize 事件中重新绑定或使用 ResizeObserver 同步更新裁剪逻辑;
- 无障碍考量:该效果属装饰性交互,无需额外 ARIA 标注;但应确保基础文字内容在无 JS 时仍可读(即 .base 层始终可见)。
此方案摒弃了复杂的位置插值与逐字符操作,以声明式 CSS 裁剪替代命令式 DOM 操作,代码简洁、性能优异、易于维护,是实现“鼠标驱动文字分色”效果的专业级实践。










