马黑黑 发表于 2025-7-29 22:44

万花筒

<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>

马黑黑 发表于 2025-7-29 22:44

代码

<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>

马黑黑 发表于 2025-7-29 22:58

实现思路:

根据图片实际尺寸设计 #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中完成。

马黑黑 发表于 2025-7-29 23:00

也可以反其道而行之:先是完好的图形,指针移入或触碰是将其打散。

这需要调整一些设置和语句置。

马黑黑 发表于 2025-7-29 23:01

另外还可以加入一个变量,用以规定每一个子元素的 transition delay(延时),这样的结果可能会更为奇妙。

马黑黑 发表于 2025-7-29 23:03

子元素越多,运行效果越好,不过太多的HTML元素会对系统资源产生一定影响,一般建议在100个以内较好。如果子元素数量较多,就尽量不要设置子元素阴影,阴影时十分消耗资源的。

马黑黑 发表于 2025-7-29 23:04

这个创意也可以命名为“破镜重圆”{:4_170:}

小文 发表于 2025-7-29 23:05

好神奇!问好先生

马黑黑 发表于 2025-7-29 23:21

小文 发表于 2025-7-29 23:05
好神奇!问好先生

晚上好

杨帆 发表于 2025-7-30 00:35

巧妙的设计,奇妙的实现,美妙的效果,谢谢马老师精彩分享{:4_190:}

梦江南 发表于 2025-7-30 09:28

这个创意也可以命名为“破镜重圆”,有意思!太神奇了!{:4_187:}

红影 发表于 2025-7-30 11:45

马黑黑 发表于 2025-7-29 23:00
也可以反其道而行之:先是完好的图形,指针移入或触碰是将其打散。

这需要调整一些设置和语句置。

如果是小播,肯定是鼠标触碰就归拢才对,这样更容易操作暂停等{:4_204:}

红影 发表于 2025-7-30 11:47

马黑黑 发表于 2025-7-29 23:01
另外还可以加入一个变量,用以规定每一个子元素的 transition delay(延时),这样的结果可能会更为奇妙。

那碎的过程更是支离破碎了,很有慢镜头的感觉,跟枪打在身上血花绽开一样{:4_173:}

红影 发表于 2025-7-30 11:51

一进来就发现这个万花筒好碎啊,合并起来才发现,这个图案本来切割就会变得很碎。
换了张整齐的图案去试,果然没那么碎,是方形的小块{:4_173:}

红影 发表于 2025-7-30 11:54

马黑黑 发表于 2025-7-29 23:04
这个创意也可以命名为“破镜重圆”

还是叫万花筒好,更形象,如果想叫破镜重圆,就弄个镜子的图图?{:4_173:}

马黑黑 发表于 2025-7-30 12:40

红影 发表于 2025-7-30 11:54
还是叫万花筒好,更形象,如果想叫破镜重圆,就弄个镜子的图图?

也行

马黑黑 发表于 2025-7-30 12:42

红影 发表于 2025-7-30 11:51
一进来就发现这个万花筒好碎啊,合并起来才发现,这个图案本来切割就会变得很碎。
换了张整齐的图案去试, ...

本身就是切成方块的。可以考虑切成方块后再一分为二,用伪元素替代主元素装载背景图片,伪元素切成三角形,代码量会大一些。

马黑黑 发表于 2025-7-30 12:43

红影 发表于 2025-7-30 11:47
那碎的过程更是支离破碎了,很有慢镜头的感觉,跟枪打在身上血花绽开一样

差不多吧

马黑黑 发表于 2025-7-30 12:43

杨帆 发表于 2025-7-30 00:35
巧妙的设计,奇妙的实现,美妙的效果,谢谢马老师精彩分享

{:4_191:}

马黑黑 发表于 2025-7-30 12:43

梦江南 发表于 2025-7-30 09:28
这个创意也可以命名为“破镜重圆”,有意思!太神奇了!

{:4_190:}
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 万花筒