如何用原生JavaScript实现CSS裁剪蒙版的向下动画效果
嘿,我来帮你搞定这个clip-path的平滑动画问题!首先得说下你当前代码里的小问题:你用style.clip去修改裁剪效果,但实际CSS里用的是clip-path(包括-webkit-前缀),这俩是不同的属性,得操作正确的那个才行。另外直接修改属性值不会有动画,因为clip-path的变化默认没有过渡效果,下面给你两种纯原生JS的实现方案,都不用jQuery~
方案1:CSS过渡+自定义属性(简洁省心)
这种方法利用CSS的transition自动处理动画,只需要用JS修改自定义属性的值就行,代码量少还流畅:
第一步:修改你的CSS
给#duotonetop添加过渡效果,并用自定义属性定义裁剪区域的上下值:
#duotonetop { padding: 0; /* 用自定义属性存裁剪的上下百分比 */ --clip-top: 0%; --clip-bottom: 90%; -webkit-clip-path: inset(var(--clip-top) 0 var(--clip-bottom) 0); clip-path: inset(var(--clip-top) 0 var(--clip-bottom) 0); /* 添加过渡动画,时长可以自己调,这里设为1秒 */ transition: -webkit-clip-path 1s ease, clip-path 1s ease; height: auto; position: fixed; display: block; transform: translateY(-500px); }
第二步:更新JS函数
现在只要修改自定义属性的值,过渡动画就会自动生效:
function bottomClip() { const el = document.getElementById("duotonetop"); el.style.setProperty('--clip-top', '90%'); el.style.setProperty('--clip-bottom', '0%'); } function reClip() { const el = document.getElementById("duotonetop"); el.style.setProperty('--clip-top', '0%'); el.style.setProperty('--clip-bottom', '90%'); }
点击图片的时候,裁剪蒙版就会平滑地从顶部滑到底部啦~
方案2:用requestAnimationFrame手动控帧(更灵活)
如果你想精细控制动画的节奏、缓动曲线,就用原生JS的requestAnimationFrame逐帧更新裁剪值:
替换你的JS函数
// 通用动画函数:控制clip-path从起始值过渡到目标值 function animateClipPath(el, startTop, endTop, startBottom, endBottom, duration) { const startTime = performance.now(); function updateFrame(currentTime) { const elapsed = currentTime - startTime; // 计算动画进度(0到1) let progress = Math.min(elapsed / duration, 1); // 可选:换成ease-in-out缓动曲线,动画更自然 progress = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; // 计算当前帧的裁剪值 const currentTop = startTop + (endTop - startTop) * progress; const currentBottom = startBottom + (endBottom - startBottom) * progress; // 设置裁剪属性 el.style.webkitClipPath = `inset(${currentTop}% 0 ${currentBottom}% 0)`; el.style.clipPath = `inset(${currentTop}% 0 ${currentBottom}% 0)`; // 没完成的话继续下一帧 if (progress < 1) { requestAnimationFrame(updateFrame); } } requestAnimationFrame(updateFrame); } // 触发向下动画 function bottomClip() { const el = document.getElementById("duotonetop"); // 从top=0%/bottom=90% 动画到 top=90%/bottom=0%,时长1000ms animateClipPath(el, 0, 90, 90, 0, 1000); } // 还原初始状态 function reClip() { const el = document.getElementById("duotonetop"); animateClipPath(el, 90, 0, 0, 90, 1000); }
这个方案可以随意调整动画时长、缓动效果,适合需要定制化动画的场景。
完整代码示例(用方案1)
CSS(style.css)
@font-face { font-family: Fraktur; src: url(typefaces/BreitkopfFraktur.ttf); } @font-face { font-family: Noe; src: url(typefaces/noe.ttf); } html { background-image: url(images/hero.jpg); overflow-x: hidden; overflow-y: auto; } body { text-align: center; overflow: hidden; margin: 0 !important; padding: 0 !important; } h1 { font-family: Fraktur; margin-top: 15%; color: white; font-size: 12em; display: inline; } #duotonetop { padding: 0; --clip-top: 0%; --clip-bottom: 90%; -webkit-clip-path: inset(var(--clip-top) 0 var(--clip-bottom) 0); clip-path: inset(var(--clip-top) 0 var(--clip-bottom) 0); transition: -webkit-clip-path 1s ease, clip-path 1s ease; height: auto; position: fixed; display: block; transform: translateY(-500px); } .cont { margin-top: 15%; }
HTML
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="css/style.css"> </head> <body> <center> <div class="cont"> <span class="js-animate" data-speed="2" data-position="top" style="transform: translate3d(0px, 0px, 0px);"> <h1>a</h1> </span> <h1>m</h1> <h1>s</h1> <h1>t</h1> <h1>e</h1> <h1>r</h1> <h1>d</h1> <h1>a</h1> <h1>m</h1> </div> </center> <a onclick="bottomClip()"><img id="duotonetop" src="css/images/hero_duotone.png"></a> <script> function bottomClip() { const el = document.getElementById("duotonetop"); el.style.setProperty('--clip-top', '90%'); el.style.setProperty('--clip-bottom', '0%'); } function reClip() { const el = document.getElementById("duotonetop"); el.style.setProperty('--clip-top', '0%'); el.style.setProperty('--clip-bottom', '90%'); } </script> </body> </html>
内容的提问来源于stack exchange,提问作者Jodast
相关产品推荐
相关产品推荐

