实现思路:
使用元素和伪元素交换背景图像达成切换图像的设计:开始时头一个图像在元素背景上呈现,伪元素什么都不加载,从第一次切换开始,伪元素事先加载一个新图像,同时使用 conic-gradient 对其进行遮罩,并运行改变遮罩色标终止角度的动画使得伪元素上的背景渐次绕圈呈现,动画绕圈的起始角度随机,动画完成后将伪元素上的背景图象移交给主元素背景,如此往复运行。
为让上述思路变为现实,需要设计几个CSS变量:其一,--start,锥形渐变(基于圆的)起始角度,它将控制(在圆周上)放开遮罩的开始点,因为锥形渐变是绕中心点做顺时针圆周渐变的;其二,--bg1,存储主元素的背景图像数据;其三,--bg2,存储伪元素的背景图象信息。这些变量的控制权交给JS:每一次转场图像动画的触发和实施过程都会动态地更新这些变量值。下面是具体代码,可在线运行:
<style>
#ma {
position: relative;
margin: 30px auto;
width: 400px;
height: 400px;
background: var(--bg1); /* 背景变量由JS控制 */
border-radius: 50%;
}
#ma::after {
position: absolute;
content: '';
inset: 0;
background: var(--bg2); /* 背景变量由JS控制 */
border-radius: 50%;
/* 锥形渐变转场 :开始角度、色标变量通过JS控制 */
mask: conic-gradient(from var(--start), transparent var(--deg) , var(--deg), red);
}
</style>
<div id="ma">点击转场</div>
<script>
// deg : 遮罩色标开始值,step : 色标值改变系数,
// currentBg : 当前背景,raf : requestAnimationFrame计数器
let deg = 360, step = 5, currentBg, raf;
// 设置随机背景色+随机遮罩角度
const setRadBg = (elm, val, bg = null) => {
// 如果调用者不提供 bg 参数则使用随机背景色
if (!bg) bg = `#${Math.random().toString(16).substring(2, 8)}`;
elm.style.setProperty(val, bg); // 设置 elm 元素的 val 背景色
elm.style.setProperty('--start', Math.random() * 360 + 'deg'); // 设置随机遮罩起始角度
return bg; // 返回 bg 值
};
/* 遮罩动画 */
const animate = () => {
if (deg < 0) { // 如果色标角度小于 0
cancelAnimationFrame(raf); // 取消 raf 计数器
deg = 360; // 色标值回到初始值
setRadBg(ma, '--bg1', currentBg); // 调用 setRadBg 函数 : 当前颜色值做主元素背景色
} else { // 否则
deg -= step; // 色标值递减
ma.style.setProperty('--deg', deg + 'deg'); // 更新元素的色标值
raf = requestAnimationFrame(animate); // 更新并存储 raf 计数器
}
};
currentBg = setRadBg(ma, '--bg1'); // 首次运行 setRadBg 函数 : 初始化界面并存储当前背景
// 元素点击事件
ma.onclick = () => {
currentBg = setRadBg(ma, '--bg2'); // 运行 setRadBg 函数并存储当前背景
animate(); // 运行转场动画
};
</script>
【附】conic-gradient 锥形渐变简洁:
锥形渐变默认以元素的圆心作为中心点,参与渐变的颜色围绕圆心从 0 度(指向正上方)开始、按顺时针做渐变,开始颜色和结束颜色在元素的上半部分的中央存在明显的硬线衔接痕迹。下面例子是元素背景图像由天蓝色和红色参与渐变,查看预览效果可以更好理解默认设置下的锥形渐变效果:
<style>
.ma {
margin: 30px;
width: 200px;
height: 200px;
background: conic-gradient(skyblue, red); /* 锥形渐变背景 */
}
</style>
<div class="ma"></div>
再提供几个其它例子,这些例子展示简单的个性化锥形渐变设置:
<style>
.ma {
margin: 30px 0 30px 20px;
width: 200px;
height: 200px;
display: inline-block;
}
.ma:nth-of-type(1) {
/* 渐变从90度开始 */
background: conic-gradient(from 90deg, red, green, blue);
}
.ma:nth-of-type(2) {
/* 渐变从90的开始,中心点不在圆心 */
background: conic-gradient(from 90deg at 20% 60% , red, green, blue);
}
.ma:nth-of-type(3) {
/* 色标边界硬线衔接 :除百分比外还可以用 deg 做角度单位 */
background: conic-gradient(from 90deg, red 33.3%, green 33.3%, green 66.6%, blue 66.6%, blue);
}
.ma:nth-of-type(4) {
/* 饼状图 */
background: conic-gradient(red 120deg, orange 120deg, orange 240deg, yellow 240deg, yellow);
border-radius: 50%;
}
.ma:nth-of-type(5) {
/* 非标准的七彩虹色盘效果 */
background: conic-gradient(red,yellow,green,cyan,blue,magenta,red);
border-radius: 50%;
}
.ma:nth-of-type(6) {
/* 重复性锥形渐变 */
background: repeating-conic-gradient(hsla(0, 0%, 100%, 0.2) 0deg 15deg, hsla(0, 0%, 100%, 0) 0deg 30deg) tan;
border-radius: 50%;
}
</style>
<div class="ma"></div>
<div class="ma"></div>
<div class="ma"></div>
<div class="ma"></div>
<div class="ma"></div>
<div class="ma"></div>