万花筒
<style>#pa {
margin: 20px auto;
width: 750px;
height: 600px;
display: grid;
place-items: center;
position: relative;
}
#ma {
position: absolute;
width: 398px;
height: 398px;
transform: scale(1);
}
#ma:hover .son {
transform: unset;
}
.son {
--angle: 0;
position: absolute;
background: url('https://638183.freep.cn/638183/small/fi1.webp') no-repeat var(--x1) var(--y1);
transform: rotate(var(--angle)) translate(160px);
transition: 2s;
}
</style>
<div id="pa">
<div id="ma"></div>
</div>
<script>
const rows = 8, cols = 8, size = 398;
const ww = size / cols, hh = size / rows;
for (let j = 0; j < rows; j ++) {
for (let k = 0; k < cols; k ++) {
const son = document.createElement('div');
son.className = 'son';
son.style.cssText += `
width: ${ww}px;
height: ${hh}px;
left: ${k * ww}px;
top: ${j * hh}px;
--x1: ${-1 * k * ww}px;
--y1: ${-1 * j * hh}px;
--angle: ${360 * Math.random()}deg;
`;
ma.appendChild(son);
}
}
</script> 代码
<style>
#pa {
margin: 20px auto;
width: 750px;
height: 600px;
display: grid;
place-items: center;
position: relative;
}
#ma {
position: absolute;
width: 398px;
height: 398px;
transform: scale(1);
}
#ma:hover .son {
transform: unset;
}
.son {
--angle: 0;
position: absolute;
background: url('https://638183.freep.cn/638183/small/fi1.webp') no-repeat var(--x1) var(--y1);
transform: rotate(var(--angle)) translate(160px);
transition: 2s;
}
</style>
<div id="pa">
<div id="ma"></div>
</div>
<script>
const rows = 8, cols = 8, size = 398;
const ww = size / cols, hh = size / rows;
for (let j = 0; j < rows; j ++) {
for (let k = 0; k < cols; k ++) {
const son = document.createElement('div');
son.className = 'son';
son.style.cssText += `
width: ${ww}px;
height: ${hh}px;
left: ${k * ww}px;
top: ${j * hh}px;
--x1: ${-1 * k * ww}px;
--y1: ${-1 * j * hh}px;
--angle: ${360 * Math.random()}deg;
`;
ma.appendChild(son);
}
}
</script>
实现思路:
根据图片实际尺寸设计 #ma 的宽高,它是容器,里面会加载N多个子元素。
子元素 .son 需要几个CSS变量,其中,--angle 是分散的随机角度,--x1 是left属性值的依据同时还是背景图片截取依据,--y1 是top属性值和背景图片的截取依据。这些变量,都在JS中赋值。
JS代码中,设计了 8 * 8 的行(rows)列(cols),图片宽高 size 为 398,然后计算一下 .son 的宽高放到 ww 和 hh 两个变量中存储,后面会用到。
用双 for循环创建行列子元素 son,根据排列规律一一给 son 子元素的相关属性和变量赋值,最后将子元素一一追加到 ma 中。
在CSS设计里,子元素 son 通过 transform 属性按 --angle 个角度和 160个像素打散安放,#ma:hover .son 选择器则将 transform 重置,子元素将各归其位。
构图核心:代码在第 22 行、44和45行——
所有子元素使用同一张图片做背景图,背景图截取算法在JS中完成。 也可以反其道而行之:先是完好的图形,指针移入或触碰是将其打散。
这需要调整一些设置和语句置。 另外还可以加入一个变量,用以规定每一个子元素的 transition delay(延时),这样的结果可能会更为奇妙。 子元素越多,运行效果越好,不过太多的HTML元素会对系统资源产生一定影响,一般建议在100个以内较好。如果子元素数量较多,就尽量不要设置子元素阴影,阴影时十分消耗资源的。 这个创意也可以命名为“破镜重圆”{:4_170:} 好神奇!问好先生 小文 发表于 2025-7-29 23:05
好神奇!问好先生
晚上好 巧妙的设计,奇妙的实现,美妙的效果,谢谢马老师精彩分享{:4_190:} 这个创意也可以命名为“破镜重圆”,有意思!太神奇了!{:4_187:} 马黑黑 发表于 2025-7-29 23:00
也可以反其道而行之:先是完好的图形,指针移入或触碰是将其打散。
这需要调整一些设置和语句置。
如果是小播,肯定是鼠标触碰就归拢才对,这样更容易操作暂停等{:4_204:} 马黑黑 发表于 2025-7-29 23:01
另外还可以加入一个变量,用以规定每一个子元素的 transition delay(延时),这样的结果可能会更为奇妙。
那碎的过程更是支离破碎了,很有慢镜头的感觉,跟枪打在身上血花绽开一样{:4_173:} 一进来就发现这个万花筒好碎啊,合并起来才发现,这个图案本来切割就会变得很碎。
换了张整齐的图案去试,果然没那么碎,是方形的小块{:4_173:} 马黑黑 发表于 2025-7-29 23:04
这个创意也可以命名为“破镜重圆”
还是叫万花筒好,更形象,如果想叫破镜重圆,就弄个镜子的图图?{:4_173:} 红影 发表于 2025-7-30 11:54
还是叫万花筒好,更形象,如果想叫破镜重圆,就弄个镜子的图图?
也行 红影 发表于 2025-7-30 11:51
一进来就发现这个万花筒好碎啊,合并起来才发现,这个图案本来切割就会变得很碎。
换了张整齐的图案去试, ...
本身就是切成方块的。可以考虑切成方块后再一分为二,用伪元素替代主元素装载背景图片,伪元素切成三角形,代码量会大一些。 红影 发表于 2025-7-30 11:47
那碎的过程更是支离破碎了,很有慢镜头的感觉,跟枪打在身上血花绽开一样
差不多吧 杨帆 发表于 2025-7-30 00:35
巧妙的设计,奇妙的实现,美妙的效果,谢谢马老师精彩分享
{:4_191:} 梦江南 发表于 2025-7-30 09:28
这个创意也可以命名为“破镜重圆”,有意思!太神奇了!
{:4_190:}