魔幻立体球演示
<style>#player {
margin: 100px 0 100px calc(50% - 150px);
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
background: radial-gradient(beige, skyblue);
perspective: 600px;
transform-style: preserve-3d;
}
.ring {
position: absolute;
width: 100%;
height: 100%;
border: thick dashed var(--cc);
border-radius: 50%;
transform: translateZ(-30px) rotateX(var(--ax)) rotateY(var(--ay));
}
</style>
<div id="player" title="播放/暂停"></div>
<script>
var total = 15, rings = [], step = 0.5, isRun = false, raf;
Array.from({length: total}).forEach( (d,k) => {
d = document.createElement('div');
d.className = 'ring';
const a = k * 360 / total;
d.style.cssText += `
--ax: ${a}deg;
--ay: ${a}deg;
--cc: #${Math.random().toString(16).substring(2,8)};
`;
rings.push({ elm: d, a: a });
player.appendChild(d);
});
const animate = () => {
rings.forEach( (d, k) => {
d.a = d.a + step;
d.elm.style.setProperty('--ax', d.a + 'deg');
d.elm.style.setProperty('--ay', d.a + 'deg');
});
raf = requestAnimationFrame(animate);
};
player.onclick = () => {
isRun = !isRun;
isRun ? animate() : cancelAnimationFrame(raf);
};
</script> 代码
<style>
#player {
margin: 100px 0 100px calc(50% - 150px);
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
background: radial-gradient(beige, skyblue);
perspective: 600px;
transform-style: preserve-3d;
}
.ring {
position: absolute;
width: 100%;
height: 100%;
border: thick dashed var(--cc);
border-radius: 50%;
transform: translateZ(-30px) rotateX(var(--ax)) rotateY(var(--ay));
}
</style>
<div id="player" title="播放/暂停"></div>
<script>
var total = 15, rings = [], step = 0.5, isRun = false, raf;
Array.from({length: total}).forEach( (d,k) => {
d = document.createElement('div');
d.className = 'ring';
const a = k * 360 / total;
d.style.cssText += `
--ax: ${a}deg;
--ay: ${a}deg;
--cc: #${Math.random().toString(16).substring(2,8)};
`;
rings.push({ elm: d, a: a });
player.appendChild(d);
});
const animate = () => {
rings.forEach( (d, k) => {
d.a = d.a + step;
d.elm.style.setProperty('--ax', d.a + 'deg');
d.elm.style.setProperty('--ay', d.a + 'deg');
});
raf = requestAnimationFrame(animate);
};
player.onclick = () => {
isRun = !isRun;
isRun ? animate() : cancelAnimationFrame(raf);
};
</script>
CSS和HTML:
容器元素 player 设置为 300*300 的尺寸,子元素 ring 圆环每一个都和父元素一样大小,然后在X轴、Y轴上均匀旋转,使用的CSS变量分别是 --ax、--ay,它们在后续JS中赋值,--ax 其实等于 --ay,之所以设置两个变量,最初考虑是让这两个值有所不同——这也许是另一种可能。
translateZ(-30px) 仅是在层次上做一点点距离拉开,不要的话默认圆环在Z轴上都是0.
JS相对简单:
变量 total 是圆环总数,rings 是圆环数组,step 是圆环旋转幅度,isRun 是动画运行开关,raf 是请求关键帧动画 requestanimationframe ID。
根据 total 变量创建圆环,圆环使用 div 标签,CSS类名为 ring,圆环的旋转角度平均化,并记录圆环的名称和所分配的角度到数组 rings 中。
动画函数 animate,遍历 rings 数组,改变其角度值,并将·改变的值设置到 --ax 和 --ay 这两个CSS变量,然后通过 requestanimationframe API 递归调用函数自身,形成持续运行动画的效果。
动画可控。作为演示,使用 player 的点击事件来完成:每一次单击它时,动画开关变量取反,即真时变为假、假时变为真,然后依据 isRun 的值决定时播放动画还是取消动画。 圆环边框有多种选择,包括粗细、样式在内。圆环边框颜色可以不随机。
step 角度增幅可以根据需要设置为不同的数值。 这些圆环因为有立体的远近而线条的粗细不同,随着角度变化着,很奇妙{:4_199:} 奇妙的构思,魔幻的效果,谢谢马老师经典讲授与分享{:4_190:} 杨帆 发表于 2025-7-19 21:05
奇妙的构思,魔幻的效果,谢谢马老师经典讲授与分享
{:4_191:} 红影 发表于 2025-7-19 20:44
这些圆环因为有立体的远近而线条的粗细不同,随着角度变化着,很奇妙
CSS的真三维和模拟三维是不一样的 马黑黑 发表于 2025-7-19 23:53
CSS的真三维和模拟三维是不一样的
还有真三维?不是都是模拟的么? 红影 发表于 2025-7-20 14:23
还有真三维?不是都是模拟的么?
你设置了 perspective 和 transform 3d,它就是真三维的模拟,假三维模拟指通过阴影等手段实现,不启用三维视图。 马黑黑 发表于 2025-7-20 16:07
你设置了 perspective 和 transform 3d,它就是真三维的模拟,假三维模拟指通过阴影等手段实现,不启用三 ...
哦,假三维是指阴影等手段的运用啊。嗯嗯,知道了{:4_187:} 红影 发表于 2025-7-20 18:51
哦,假三维是指阴影等手段的运用啊。嗯嗯,知道了
{:4_190:} 马黑黑 发表于 2025-7-20 18:58
其实都不是真的,只是假三维的更假点{:4_173:}
页:
[1]