radial+mask实现图片转场效果
本帖最后由 马黑黑 于 2025-8-15 20:31 编辑 <br /><br /><div class="codebox" data-prev="1"><style>
#ma {
position: relative;
margin: 30px auto;
width: 400px;
height: 530px;
background: var(--bg);
color: red;
<txt-green>/* 主元素背景使用JS图片数组中的第 1 张图片 */</txt-green>
--bg: url('https://638183.freep.cn/638183/t22/hl/bw1.jpg') no-repeat center/cover;
<txt-green>/* 伪元素背景使用JS图片数组中的第 2 张图片 */</txt-green>
--bg1: url('https://638183.freep.cn/638183/t22/hl/bw2.jpg') no-repeat center/cover;
--per: 0%; <txt-green>/* 色标边界变量 */</txt-green>
}
#ma::before {
position: absolute;
content: '';
inset: 0;
background: var(--bg1);
<txt-green>/* 遮罩设定 : 圆形遮罩(椭圆遮罩则将 circle, 删掉) */</txt-green>
mask: radial-gradient(circle, red var(--per), transparent var(--per) 0);
--webkit-mask: radial-gradient(circle, red var(--per), transparent var(--per) 0);
}
</style>
<div id="ma" title="点击转场"></div>
<script>
var per = 0, <txt-green>// 遮罩渐变色标边界</txt-green>
step = 1, <txt-green>// 色标边界变化歩幅</txt-green>
picIdx = 0, <txt-green>// 图片序号</txt-green>
isPlaying = false, <txt-green>// 遮罩动画是否运行中</txt-green>
raf; <txt-green>// 请求关键帧动画计数器</txt-green>
<txt-green>// 图片数组(多少任意)</txt-green>
var pics = [
'https://638183.freep.cn/638183/t22/hl/bw1.jpg',
'https://638183.freep.cn/638183/t22/hl/bw2.jpg',
'https://638183.freep.cn/638183/t22/hl/bw3.jpg',
'https://638183.freep.cn/638183/t22/hl/bw4.jpg',
'https://638183.freep.cn/638183/t22/hl/bw5.jpg',
'https://638183.freep.cn/638183/t22/hl/bw6.jpg'
];
<txt-green>// 更新图片(背景图片序号的计算需要做取余数处理)</txt-green>
const update = () => {
if (isPlaying) return; <txt-green>// 若请求关键帧动画正在运行中则不执行此函数</txt-green>
<txt-green>// 如果当前使用的图片序号为偶数 :</txt-green>
if (picIdx % 2 === 0) {;
<txt-green>// 主元素背景使用伪元素的背景图片</txt-green>
ma.style.setProperty('--bg', `url(${pics}) no-repeat center/cover`);
<txt-green>// 伪元素背景使用下一张图片</txt-green>
ma.style.setProperty('--bg1', `url(${pics[(picIdx + 1) % pics.length]}) no-repeat center/cover`);
<txt-green>// 否则假如是奇数 :</txt-green>
} else {
<txt-green>// 伪元素背景使用当前图片序号对应的图片</txt-green>
ma.style.setProperty('--bg1', `url(${pics}) no-repeat center/cover`);
<txt-green>// 主元素背景使用下一张图片</txt-green>
ma.style.setProperty('--bg', `url(${pics[(picIdx + 1) % pics.length]}) no-repeat center/cover`);
}
picIdx ++; <txt-green>// 图片序号递增</txt-green>
animate(); <txt-green>// 运行遮罩动画</txt-green>
};
<txt-green>// 遮罩动画</txt-green>
const animate = () => {
per += step; <txt-green>// 色标边界变量递增(或递减)</txt-green>
<txt-green>// 若色标变量小于 0 或 大于 100 :</txt-green>
if (per < 0 || per > 100) {
cancelAnimationFrame(raf); <txt-green>// 取消请求关键帧动画计数器</txt-green>
step = -step; <txt-green>// 歩幅正负互变</txt-green>
isPlaying = false; <txt-green>// 此时遮罩动画运行状态为假</txt-green>
<txt-green>// 否则 :</txt-green>
} else {
ma.style.setProperty('--per', per + '%'); <txt-green>// 将 per 变量传递给CSS变量 --per</txt-green>
raf = requestAnimationFrame(animate); <txt-green>// 递归运行函数自身(以持续改变色标边界)</txt-green>
isPlaying = true; <txt-green>// 此时遮罩动画运行状态为真</txt-green>
}
};
ma.onclick = () => update();
</script>
</div>
<script type="module">
import linenumber from 'https://638183.freep.cn/638183/web/js/linenumber.js';
linenumber();
</script> 本帖最后由 马黑黑 于 2025-8-15 20:42 编辑
实现原理简单解释:
(一)打开页面即初始化之时,通过CSS设定,主元素和伪元素分别使用JS图片数组中的第一张和第二张图片做背景,伪元素被全遮罩,主元素呈现图片;
(二)随后的图片转场,主元素和伪元素一次轮换呈现图片,以变量 picIdx 取 2 的余数值为依据分别给主元素、伪元素设置背景;
(三)转场总是通过遮罩、揭开遮罩依次进行。
radial-gradient 径向渐变默认使用椭圆形状,当元素高一致时是为圆形形状,不一致时默认是为椭圆形状,可以像本例 21、22 行代码那样强制使用圆形形状。 新的图片转场效果又诞生了,谢谢马老师精彩示范与讲授 <p>一楼的 update 函数写的比较罗嗦,修改一下:</p>
<div class="codebox">
const update = () => {
if (isPlaying) return;
var idx = (picIdx % 2 === 0 ? picIdx : picIdx + 1) % pics.length,
idx1 = (picIdx % 2 === 0 ? picIdx + 1 : picIdx) % pics.length;
ma.style.setProperty('--bg', `url(${pics}) no-repeat center/cover`);
ma.style.setProperty('--bg1', `url(${pics}) no-repeat center/cover`);
picIdx ++;
animate();
};
</div> 马黑黑 发表于 2025-8-15 20:28
实现原理简单解释:
(一)打开页面即初始化之时,通过CSS设定,主元素和伪元素分别使用JS图片数组中的 ...
分别是在奇偶数的转换过程中,遮罩半径在0%和100%之间转换,这思路真巧妙{:4_199:} 马黑黑 发表于 2025-8-15 20:44
radial-gradient 径向渐变默认使用椭圆形状,当元素高一致时是为圆形形状,不一致时默认是为椭圆形状,可以 ...
原来还可以把径向渐变的椭圆强制改变成圆形{:4_204:} 红影 发表于 2025-8-15 21:57
原来还可以把径向渐变的椭圆强制改变成圆形
就这两种形状,默认椭圆,还可以设置中心点:
radiao-gradient(at 20% 20, red, transparent,green);
或使用圆形形状:
radial-gradient(circle at 20% 20%, red, transparent, red); 红影 发表于 2025-8-15 21:55
分别是在奇偶数的转换过程中,遮罩半径在0%和100%之间转换,这思路真巧妙
笨人用巧法{:4_170:} 杨帆 发表于 2025-8-15 20:57
新的图片转场效果又诞生了,谢谢马老师精彩示范与讲授
{:4_191:} 小辣椒欣赏加学习{:4_187:} 小辣椒 发表于 2025-8-15 22:38
小辣椒欣赏加学习
{:4_190:} 这次有方向区别了,由内到外,或者由外到内。。
关键是--per的变化,0至100或者100至0,
所以若色标变量小于 0 或 大于 100,就歩幅正负互变进行step = -step;
太喵了喵喵。。。。。{:4_173:} 花飞飞 发表于 2025-8-15 22:53
这次有方向区别了,由内到外,或者由外到内。。
关键是--per的变化,0至100或者100至0,
所以若色标变量 ...
这是巧妙完成预设目标的方法 马黑黑 发表于 2025-8-15 20:28
实现原理简单解释:
(一)打开页面即初始化之时,通过CSS设定,主元素和伪元素分别使用JS图片数组中的 ...
表面看着只是形状的 变化,实际上运行根本不同{:4_173:} 马黑黑 发表于 2025-8-15 22:33
就这两种形状,默认椭圆,还可以设置中心点:
radiao-gradient(at 20% 20, red, transparent,green);
椭圆的也好玩,横竖斜方向随机的吧 花飞飞 发表于 2025-8-15 22:54
表面看着只是形状的 变化,实际上运行根本不同
不同的渐变遮罩以及遮罩设计方案,实现的细节自然不一样。 花飞飞 发表于 2025-8-15 22:55
椭圆的也好玩,横竖斜方向随机的吧
中心点默认在元素的中心。如果需要随机中心点,可以参考 conic 设置随机开始角度的方法设置随机圆心:
mask: radial-gradient(circle at var(--cx) var(--cy), 颜色...);
然后在JS相应的地方处理 --cx 和 --cy 变量 马黑黑 发表于 2025-8-15 22:54
这是巧妙完成预设目标的方法
这灵巧的超标了,厉害。。
主要是这么难的东东被你写得小白也能有点点看懂。。更厉害。。{:4_170:} 马黑黑 发表于 2025-8-15 22:56
不同的渐变遮罩以及遮罩设计方案,实现的细节自然不一样。
每种都有自己的独特风格,举一反三是行不通了{:4_173:}