马黑黑 发表于 2025-7-27 07:52

Purple Magic

<style>
    #pa { --per: 0%; 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/6/rc02.jpg') no-repeat center/cover, rgba(0,128,0,.45); background-blend-mode: difference; box-shadow: 2px 2px 8px #000; z-index: 1; overflow: hidden; position: relative; }
    #pa::after { content: ''; position: absolute; width: 100%; height: 100%; background: url('https://638183.freep.cn/638183/t24/6/rc02.jpg') no-repeat center/cover; clip-path: polygon(0 calc(100% - var(--per)), var(--per) 100%, 100% 100%, 100% var(--per), calc(100% - var(--per)) 0, 0 0); transition: 1s; }
    #pa:hover { --per: 100%; }
    #player { position: absolute; bottom: 100px; left: 100px; height: 120px; width: 120px; cursor: pointer; transform-style: preserve-3d; animation: rot 6s linear infinite var(--state); }
    li-zi { --hh: 35%; position: absolute; left: -50%; top: calc(50% - var(--hh)); width: 100%; height: var(--hh); background: radial-gradient(circle at 10% 10%, red, purple); border-radius: 50% 100% 0 100%; box-shadow: inset 0 0 30px lightblue, 2px 4px 16px rgba(0,0,0,.35); transform-origin: 100% 100%; }
    #btnFs { left: 20px; bottom: 20px; color: #eee; }
    .vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); opacity: .45; z-index: 9; pointer-events: none; }
    @keyframes rot {
      to { transform: rotate(1turn); }
    }
</style>

<div id="pa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=2697499554" autoplay loop></audio>
    <video class="vid" src="https://bpic.588ku.com/video_listen/588ku_video/25/03/05/12/16/26/video67c7d01a5fa5e.mp4" autoplay loop muted></video>
    <div id="player"></div>
</div>

<script type="module">
    import { FS } from 'https://638183.freep.cn/638183/web/js/fullscreen.js';
    FS(pa, player);
    const tt = 12;
    Array.from({length: tt}).forEach( (lz,idx) => {
      lz = document.createElement('li-zi');
      lz.style.cssText += `transform: rotate3d(0, 0.1, 1, ${idx * 360 / tt}deg);`;
      player.appendChild(lz);
    });
</script>

马黑黑 发表于 2025-7-27 07:53

参考代码

<style>
    #pa { --per: 0%; 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/6/rc02.jpg') no-repeat center/cover, rgba(0,128,0,.45); background-blend-mode: difference; box-shadow: 2px 2px 8px #000; z-index: 1; overflow: hidden; position: relative; }
    #pa::after { content: ''; position: absolute; width: 100%; height: 100%; background: url('https://638183.freep.cn/638183/t24/6/rc02.jpg') no-repeat center/cover; clip-path: polygon(0 calc(100% - var(--per)), var(--per) 100%, 100% 100%, 100% var(--per), calc(100% - var(--per)) 0, 0 0); transition: 1s; }
    #pa:hover { --per: 100%; }
    #player { position: absolute; bottom: 100px; left: 100px; height: 120px; width: 120px; cursor: pointer; transform-style: preserve-3d; animation: rot 6s linear infinite var(--state); }
    li-zi { --hh: 35%; position: absolute; left: -50%; top: calc(50% - var(--hh)); width: 100%; height: var(--hh); background: radial-gradient(circle at 10% 10%, red, purple); border-radius: 50% 100% 0 100%; box-shadow: inset 0 0 30px lightblue, 2px 4px 16px rgba(0,0,0,.35); transform-origin: 100% 100%; }
    #btnFs { left: 20px; bottom: 20px; color: #eee; }
    .vid {position: absolute; width: 100%; height: 100%; object-fit: cover; mask: radial-gradient(transparent 20%, red); -webkit-mask: radial-gradient(transparent 20%, red); opacity: .45; z-index: 9; pointer-events: none; }
    @keyframes rot {
      to { transform: rotate(1turn); }
    }
</style>

<div id="pa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=2697499554" autoplay loop></audio>
    <video class="vid" src="https://bpic.588ku.com/video_listen/588ku_video/25/03/05/12/16/26/video67c7d01a5fa5e.mp4" autoplay loop muted></video>
    <div id="player"></div>
</div>

<script type="module">
    import { FS } from 'https://638183.freep.cn/638183/web/js/fullscreen.js';
    FS(pa, player);
    const tt = 12;
    Array.from({length: tt}).forEach( (lz,idx) => {
      lz = document.createElement('li-zi');
      lz.style.cssText += `transform: rotate3d(0, 0.1, 1, ${idx * 360 / tt}deg);`;
      player.appendChild(lz);
    });
</script>

马黑黑 发表于 2025-7-27 08:02

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

帖子容器使用 background-blend-mode 将背景图片与设定颜色融合;帖子容器伪元素使用正常的同图背景并覆盖整个帖子容器,伪元素同时使用 clip-path(裁剪路径)属性对自身进行 polygon(多边形)裁剪,通过变量 --per 来达成:开始时 0% 表示什么都不裁剪,然后指针(移入移出容器)交互时 100% 表示全裁剪(露出容器真容)。

全屏时由于鼠标指针就在容器上方移不出来,伪元素头巾自动揭掉。

也可以考虑使用不同的背景图于容器和伪元素,以便令帖子的表现力更为丰厚。裁剪方式也可以是别样的。

小播设计非新,但实现细节自有特色。

梦江南 发表于 2025-7-27 09:19

真漂亮!欣赏老师的精彩音画。祝夏安!{:4_190:}

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

这个挺奇妙,还没整明白,我得想想这个怎么实现的{:4_187:}

马黑黑 发表于 2025-7-27 11:30

本帖最后由 马黑黑 于 2025-7-27 11:32 编辑

红影 发表于 2025-7-27 11:00
这个挺奇妙,还没整明白,我得想想这个怎么实现的
一切通过CSS操作,核心代码拆解如下:
/* 容器元素核心设置 */
#pa {
    --per: 0%; /* 设置一个百分比变量(用于裁剪) */
    /* ... 其它代码 */
    /* 背景图片 */
    background: url('https://638183.freep.cn/638183/t24/6/rc02.jpg') no-repeat center/cover, rgba(0,128,0,.45);
    /* ... 其它代码 */
}

/* 伪元素核心设置 */
#pa::after {
    /* ... 其它代码 */
    /* 背景图片和容器一样 */
    background: url('https://638183.freep.cn/638183/t24/6/rc02.jpg') no-repeat center/cover;
    /* 多边形裁剪路径,从矩形ABCD的左下、右上往AC对角线裁剪,例如:
       0 95%,
       5% 100,
       100% 100%,
       100% 5%,
       95% 0,
       0 0
       注意:0 和 100% 固定不变,5% 及 95% 和 100 存在算法关系
       下面用变量和式子替代非 0 非 100% 的数字
    */
    clip-path: polygon(
      0 calc(100% - var(--per)),
      var(--per) 100%,
      100% 100%,
      100% var(--per),
      calc(100% - var(--per)) 0,
      0 0
    );
    transition: 1s; /* 动画时长 */
}

/* 容器伪类选择器 :hover 改变 --per 变量值 */
#pa:hover { --per: 100%; }

红影 发表于 2025-7-27 12:01

马黑黑 发表于 2025-7-27 08:02
帖子容器使用 background-blend-mode 将背景图片与设定颜色融合;帖子容器伪元素使用正常的同图背景并覆盖 ...
终于看明白了,开始--per为0 ,多边形切割的六个点都在四个顶角上,所以不切割,那么伪元素(没混合颜色的)就覆盖了底图(混合颜色了的)也遮挡了小播。随着鼠标触动,在1s的时间里,--per从0变化到100,六个点的左下和右上开始分别顺着相邻两条边朝(0 0)和(100 100)运动,直到重合,这时伪元素被完全切割掉了,底图和小播全部出现。
鼠标移开是反向运动,重复上述过程。
开始我弄错了,还以为切了两个三角形,还在奇怪多边形只能切一个形状,这里为什么出现两个。是那个混合色把我弄糊涂了,以为是它覆盖上来了。错得离谱。现在明白了{:4_173:}

红影 发表于 2025-7-27 12:08

马黑黑 发表于 2025-7-27 11:30
一切通过CSS操作,核心代码拆解如下:

吃完饭过来就继续使劲看了,没刷新,回复完了才看到这个解说,不好意思。
嗯,开始没看到 --per: 0%; 其实在帖子代码的嘴上头,然后以为带底色的来覆盖,所以开始时弄错,弄得自己没想明白{:4_173:}

红影 发表于 2025-7-27 12:13

小播是用粒子组成的。粒子的形状和颜色设计很漂亮。
lz.style.cssText += `transform: rotate3d(0, 0.1, 1, ${idx * 360 / tt}deg);`;这里的数字也挺有讲究。

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

红影 发表于 2025-7-27 12:01
终于看明白了,开始--per为0 ,多边形切割的六个点都在四个顶角上,所以不切割,那么伪元素(没混合颜色 ...
这个设计你应该是容易理解的,难不倒高级空间测算工程师。主要是代码多了会形成理解上的干扰,加上又是连在一起些不很分明。

马黑黑 发表于 2025-7-27 12:46

红影 发表于 2025-7-27 12:13
小播是用粒子组成的。粒子的形状和颜色设计很漂亮。
lz.style.cssText += `transform: rotate3d(0, 0.1, 1 ...

其实也不是粒子,就用了 li-zi 这样的标签,标准的规范应用用 impeller、petal 乃至 leaf 这样的英文名称。主要是图个方便,不用声明 className

马黑黑 发表于 2025-7-27 12:47

红影 发表于 2025-7-27 12:08
吃完饭过来就继续使劲看了,没刷新,回复完了才看到这个解说,不好意思。
嗯,开始没看到 --per: 0%; 其 ...

理解他人的代码,尤其是没有注释说明的,一般都是个难题呢,即便是同做一个项目的同事

杨帆 发表于 2025-7-27 13:13

效果惊艳,很有特色,谢谢马老师经典讲授与分享{:4_190:}

红影 发表于 2025-7-27 15:01

马黑黑 发表于 2025-7-27 12:43
这个设计你应该是容易理解的,难不倒高级空间测算工程师。主要是代码多了会形成理解上的干扰,加上又是连 ...

开始看时弄错了,后来整明白了,谢谢黑黑{:4_187:}

红影 发表于 2025-7-27 15:02

马黑黑 发表于 2025-7-27 12:46
其实也不是粒子,就用了 li-zi 这样的标签,标准的规范应用用 impeller、petal 乃至 leaf 这样的英文名称 ...

嗯嗯,名称是自设的,其实用什么都行{:4_173:}

红影 发表于 2025-7-27 15:03

马黑黑 发表于 2025-7-27 12:47
理解他人的代码,尤其是没有注释说明的,一般都是个难题呢,即便是同做一个项目的同事

黑黑的代码逻辑清晰、严谨,设计也很奇妙,很值得学习呢和理解呢{:4_187:}

朵拉 发表于 2025-7-27 18:12

精彩,学生已交作业,请老师指正{:4_190:}

马黑黑 发表于 2025-7-27 19:07

红影 发表于 2025-7-27 15:03
黑黑的代码逻辑清晰、严谨,设计也很奇妙,很值得学习呢和理解呢

果酱果酱

马黑黑 发表于 2025-7-27 19:08

红影 发表于 2025-7-27 15:02
嗯嗯,名称是自设的,其实用什么都行

一般建议语义化,这是为了好理解

马黑黑 发表于 2025-7-27 19:08

红影 发表于 2025-7-27 15:01
开始看时弄错了,后来整明白了,谢谢黑黑

这个正常现象
页: [1] 2 3 4 5 6
查看完整版本: Purple Magic