马黑黑 发表于 2025-7-11 20:42

Antonio Mocho(问候小辣椒)

本帖最后由 马黑黑 于 2025-7-11 21:42 编辑 <br /><br /><style>
        #papa { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%); width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/w4/mocho.webp') no-repeat center/cover; perspective: 800px; box-shadow: 2px 2px 8px #000; z-index: 1; display: grid; place-items: center; position: relative; --size: 120px; --z: 300px; }
        #papa div { display: inherit; place-items: inherit; }
        #btnFs { left: 15px; bottom: 20px; color: white; }
        #box { --bg: #000; --border-color: yellow; position: absolute; bottom: 50px; width: var(--size); height: var(--size); transform-style: preserve-3d; transform: rotateX(-15deg) rotateY(30deg) rotateZ(0); }
        #lzpa { position: absolute; bottom: 50px; width: calc(var(--size) - 50px); height: calc(var(--size) - 50px); transition: transform 0.75s; transform-style: preserve-3d; }
        li-zi { position: absolute; width: 25px; height: 25px; border-radius: 50%; background: linear-gradient(35deg, skyblue, green); }
        .front { transform: rotateY(0) translateZ(calc(var(--size) / 2)); }
        .back { transform: rotateY(180deg) translateZ(calc(var(--size) / 2)); }
        .left { transform: rotateY(-90deg) translateZ(calc(var(--size) / 2)); }
        .right { transform: rotateY(90deg) translateZ(calc(var(--size) / 2)); }
        .top { transform: rotateX(90deg) translateZ(calc(var(--size) / 2)); }
        .bottom { transform: rotateX(-90deg) translateZ(calc(var(--size) / 2)); }
        .board { position: absolute; width: 100%; height: 100%; transition: transform 1s; font: bold 30px sans-serif; text-shadow: 2px 2px 4px orange; color: white; border: 3px dotted var(--border-color); background: var(--bg); opacity: 0.45; cursor: pointer; user-select: none; }
        .ani-fly { animation: fly 20s var(--delay) linear infinite; }
        @keyframes fly {
                from { transform: rotateY(0) translate3d(0, 0, var(--z)); }
                to { transform: rotateY(-360deg) translate3d(0, 0, var(--z)) rotateY(360deg); }
        }
</style>

<div id="papa">
        <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1066074" autoplay loop></audio>
        <div id="lzpa"></div>
        <div id="box">
                <div class="board front">PLAY</div>
                <div class="board back"></div>
                <div class="board left"></div>
                <div class="board right"></div>
                <div id="upboard" class="board top"></div>
                <div class="board bottom"></div>
        </div>
</div>

<script type="module">
        import { FS } from 'https://638183.freep.cn/638183/web/js/fullscreen.js'

        const total = 60;
        const lzAr = [];
        let lzRun = false;
        Array.from({ length: total }).forEach( (lz, k) => {
                lz = document.createElement('li-zi');
                lz.style.cssText += `
                        left: ${lzpa.clientWidth * Math.random()}px;
                        top: ${lzpa.clientHeight * Math.random()}px;
                        background: linear-gradient(
                                ${80 - Math.random() * 80}deg,
                                #${Math.random().toString(16).substring(2, 8)},
                                #${Math.random().toString(16).substring(2, 8)},
                                purple
                        );
                        --delay: ${-k * 20 / total}s;
                `;
                lzAr.push(lz);
                lzpa.appendChild(lz);
        });

        const boards = document.querySelectorAll('.board');

    const setAnimate = (begin = true) => {
      lzAr.forEach(lz => {
            begin ? lz.classList.add('ani-fly') : lz.classList.remove('ani-fly');
      });
    };

    const setYPos = (up = true) => {
      const yy = (papa.clientHeight / 2) * (up ? -1 : 0);
      lzpa.style.transform = `translateY(${yy}px)`;
    }

        const lzInit = () => {
      if (aud.paused) {
            setAnimate(false);
            setTimeout( () => {
                upboard.style.setProperty('transform', `rotateX(90deg) translateZ(calc(var(--size) / 2))`);
                setYPos(false);
            }, 500);
          } else {
              upboard.style.setProperty('transform', `rotateX(180deg) translateZ(300px)`);
            setYPos(true);
            setTimeout( () => {
                setAnimate(true);
            }, 500);
      }
        };

    aud.onplaying = aud.onpause = () => lzInit();

        window.onresize = () => {
      papa.style.setProperty('perspective', 800 * papa.clientWidth/1400 + 'px');
      papa.style.setProperty('--z', 300 * papa.clientWidth/1400 + 'px');
      setYPos(aud.paused ? false : true);
    }

    FS(papa, box);
</script>

马黑黑 发表于 2025-7-11 20:42

本帖最后由 马黑黑 于 2025-7-11 21:43 编辑

参考代码:
<style>
    #papa { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%); width: clamp(600px, 90vw, 1400px); height: auto; aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/w4/mocho.webp') no-repeat center/cover; perspective: 800px; box-shadow: 2px 2px 8px #000; z-index: 1; display: grid; place-items: center; position: relative; --size: 120px; --z: 300px; }
    #papa div { display: inherit; place-items: inherit; }
    #btnFs { left: 15px; bottom: 20px; color: white; }
    #box { --bg: #000; --border-color: yellow; position: absolute; bottom: 50px; width: var(--size); height: var(--size); transform-style: preserve-3d; transform: rotateX(-15deg) rotateY(30deg) rotateZ(0); }
    #lzpa { position: absolute; bottom: 50px; width: calc(var(--size) - 50px); height: calc(var(--size) - 50px); transition: transform 0.75s; transform-style: preserve-3d; }
    li-zi { position: absolute; width: 25px; height: 25px; border-radius: 50%; background: linear-gradient(35deg, skyblue, green); }
    .front { transform: rotateY(0) translateZ(calc(var(--size) / 2)); }
    .back { transform: rotateY(180deg) translateZ(calc(var(--size) / 2)); }
    .left { transform: rotateY(-90deg) translateZ(calc(var(--size) / 2)); }
    .right { transform: rotateY(90deg) translateZ(calc(var(--size) / 2)); }
    .top { transform: rotateX(90deg) translateZ(calc(var(--size) / 2)); }
    .bottom { transform: rotateX(-90deg) translateZ(calc(var(--size) / 2)); }
    .board { position: absolute; width: 100%; height: 100%; transition: transform 1s; font: bold 30px sans-serif; text-shadow: 2px 2px 4px orange; color: white; border: 3px dotted var(--border-color); background: var(--bg); opacity: 0.45; cursor: pointer; user-select: none; }
    .ani-fly { animation: fly 20s var(--delay) linear infinite; }
    @keyframes fly {
      from { transform: rotateY(0) translate3d(0, 0, var(--z)); }
      to { transform: rotateY(-360deg) translate3d(0, 0, var(--z)) rotateY(360deg); }
    }
</style>

<div id="papa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1066074" autoplay loop></audio>
    <div id="lzpa"></div>
    <div id="box">
      <div class="board front">PLAY</div>
      <div class="board back"></div>
      <div class="board left"></div>
      <div class="board right"></div>
      <div id="upboard" class="board top"></div>
      <div class="board bottom"></div>
    </div>
</div>

<script type="module">
    import { FS } from 'https://638183.freep.cn/638183/web/js/fullscreen.js'

    const total = 60;
    const lzAr = [];
    let lzRun = false;
    Array.from({ length: total }).forEach( (lz, k) => {
      lz = document.createElement('li-zi');
      lz.style.cssText += `
            left: ${lzpa.clientWidth * Math.random()}px;
            top: ${lzpa.clientHeight * Math.random()}px;
            background: linear-gradient(
                ${80 - Math.random() * 80}deg,
                #${Math.random().toString(16).substring(2, 8)},
                #${Math.random().toString(16).substring(2, 8)},
                purple
            );
            --delay: ${-k * 20 / total}s;
      `;
      lzAr.push(lz);
      lzpa.appendChild(lz);
    });

    const boards = document.querySelectorAll('.board');

    const setAnimate = (begin = true) => {
      lzAr.forEach(lz => {
            begin ? lz.classList.add('ani-fly') : lz.classList.remove('ani-fly');
      });
    };

    const setYPos = (up = true) => {
      const yy = (papa.clientHeight / 2) * (up ? -1 : 0);
      lzpa.style.transform = `translateY(${yy}px)`;
    }

    const lzInit = () => {
      if (aud.paused) {
            setAnimate(false);
            setTimeout( () => {
                upboard.style.setProperty('transform', `rotateX(90deg) translateZ(calc(var(--size) / 2))`);
                setYPos(false);
            }, 500);
      } else {
            upboard.style.setProperty('transform', `rotateX(180deg) translateZ(300px)`);
            setYPos(true);
            setTimeout( () => {
                setAnimate(true);
            }, 500);
      }
    };

    aud.onplaying = aud.onpause = () => lzInit();

    window.onresize = () => {
      papa.style.setProperty('perspective', 800 * papa.clientWidth/1400 + 'px');
      papa.style.setProperty('--z', 300 * papa.clientWidth/1400 + 'px');
      setYPos(aud.paused ? false : true);
    }

    FS(papa, box);
</script>

马黑黑 发表于 2025-7-11 20:43

本帖最后由 马黑黑 于 2025-7-11 21:03 编辑

说明:

帖子HTML结构分三层,这是出于控制的便捷性而设计的结构:

帖子容器开始
    粒子容器开始
       粒子
    粒子容器结束
    播放器容器开始
      立方体播放器
    播放器容器结束
帖子容器结束

立方体播放器和粒子是平行的第二层,各自都带有子元素:小播是立方体的两个面,粒子容器是N多个 li-zi 自定义标签。

音频联动控制机制中,通过函数 lzInite() 完成一些CSS数据设置,包括粒子容器的上下位移、粒子的绕圈运动、小播的开合等。这些控制机制有得分类封装成小函数,有得直接操作。联动控制机制用到定时器 setTimeout。

帖子动画机制自适应窗口的功能放在 window.onresize 事件中,主要调节3d动画场景视图、粒子运行的Z轴尺寸和粒子容器位置设置。

帖子实现细节中又不完美之处,例如,粒子整体上下、下降时有点生硬。

朵拉 发表于 2025-7-11 20:57

有些像开盲盒的效果,赞{:4_178:}

红影 发表于 2025-7-11 21:39

开始带文字的一面应该是在盒子前面,播放时跑到盒子外面,暂停时在盒子顶面,就无法回到盒子前面了呢。

红影 发表于 2025-7-11 21:43

马黑黑 发表于 2025-7-11 20:43
说明:

帖子HTML结构分三层,这是出于控制的便捷性而设计的结构:


这么多动作,尤其粒子的动作特别好看,放出去,散开,聚合,回到盒子,每个动作都很清晰有序。
散开旋转的粒子,在全屏时会有微小的上下移动,就是自适应窗口在起作用吧。{:4_204:}

未知名 发表于 2025-7-11 21:43

帖子做得精致,只是这背景图可否换一张{:4_203:}

马黑黑 发表于 2025-7-11 21:43

朵拉 发表于 2025-7-11 20:57
有些像开盲盒的效果,赞

这是京东盲盒{:4_170:}

马黑黑 发表于 2025-7-11 21:44

红影 发表于 2025-7-11 21:39
开始带文字的一面应该是在盒子前面,播放时跑到盒子外面,暂停时在盒子顶面,就无法回到盒子前面了呢。

ID放错地方了,谢谢提醒

红影 发表于 2025-7-11 21:44

这个是问候小辣椒的,进来就忙着看帖子,都忘了喊她。@小辣椒 亲爱的快来收礼{:4_187:}

马黑黑 发表于 2025-7-11 21:45

红影 发表于 2025-7-11 21:43
这么多动作,尤其粒子的动作特别好看,放出去,散开,聚合,回到盒子,每个动作都很清晰有序。
散开旋转 ...

这是CSS对应选择器 transition 属性在起作用:只要设置了该属性,基于指定属性的变化过程,就在该属性值内完成。

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

马黑黑 发表于 2025-7-11 21:44
ID放错地方了,谢谢提醒

呵呵,现在文字一面一直在前面了{:4_173:}

红影 发表于 2025-7-11 21:49

马黑黑 发表于 2025-7-11 21:45
这是CSS对应选择器 transition 属性在起作用:只要设置了该属性,基于指定属性的变化过程,就在该属性值 ...

这个动作的设置特别好看。粒子的排布也很奇特,层层叠叠的呢。

马黑黑 发表于 2025-7-11 21:50

红影 发表于 2025-7-11 21:47
呵呵,现在文字一面一直在前面了

这是改来改去改错的:之前是使用 去而已Sel二次托人All 获取操作标识的,最后觉得就操作一个面板,不如就加个标签ID吧,然后就加错地方了

马黑黑 发表于 2025-7-11 21:50

红影 发表于 2025-7-11 21:44
这个是问候小辣椒的,进来就忙着看帖子,都忘了喊她。@小辣椒 亲爱的快来收礼

{:4_190:}

马黑黑 发表于 2025-7-11 21:51

红影 发表于 2025-7-11 21:49
这个动作的设置特别好看。粒子的排布也很奇特,层层叠叠的呢。

这是在JS创建粒子时安排好的:粒子在其父容器内在指定范围内随机分布

杨帆 发表于 2025-7-11 22:13

构思奇特,效果惊艳,很智能的感觉{:4_191:}

借马老师美帖祝小辣椒开心幸福{:4_187:}

红影 发表于 2025-7-11 22:58

马黑黑 发表于 2025-7-11 21:50
这是改来改去改错的:之前是使用 去而已Sel二次托人All 获取操作标识的,最后觉得就操作一个面板,不如就 ...

那个加错的其实也挺好看的,很有特点呢{:4_187:}

红影 发表于 2025-7-11 23:00

马黑黑 发表于 2025-7-11 21:50


替她先谢谢黑黑的惦记,和黑黑一起祝福她安康。{:4_204:}

红影 发表于 2025-7-11 23:00

马黑黑 发表于 2025-7-11 21:51
这是在JS创建粒子时安排好的:粒子在其父容器内在指定范围内随机分布

这样的排布方式特别好,很丰富的感觉。
页: [1] 2 3 4 5 6 7 8
查看完整版本: Antonio Mocho(问候小辣椒)