马黑黑 发表于 2022-11-4 20:12

CSS+JS:3d粒子一例

<style>
#mama {}
#mama > p, #mama > pre { padding: 8px 0; }
#mama > pre { font-size: 14px; }
</style>

<div id="mama">

<p>本帖使用到CSS的3d转换知识点:</p>
<p>一、父元素声明景深:</p>
<pre><span style="color: blue;">perspective</span>: 1000px;</pre>
<p>本例景深设置为 1000px,可以是其他数值。景深针对Z轴,即眼睛和屏幕间的方向的延伸,是物体对象在这个方向上从屏幕的表面到纵深方向的距离,该距离越大,景深就越细腻。一般会根据屏幕分辨率定值。</p>
<p>二、子元素声明使用3d:</p>
<pre><span style="color: blue;">transform-style</span>: preserve-3d;</pre>
<p>三、3d关键帧动画:</p>
<pre><span style="color: red;">@keyframes move </span>{
&nbsp; &nbsp;to { <span style="color: blue;">transform</span>: rotate(0) translate3d(0, 0, 0); }
}
</pre>
<p>关键帧动画设计里,我们使用 transform 的两个转换属性 rotate(旋转)和 translate3d(3d移位),当 rotate 放前、translate或translate3d 放后,会产生物体绕圈圈旋转的效果,我们只需把要移动的物体对象定位就好,比如定位在父元素的中心点。这里,大家可能觉得奇怪,rotate 和 translate3d 咋都参数为 0 呢?这与本例设计有关:我们事先旋转了物体对象,然后通过关键帧动画恢复它们的初始状况。看完整的CSS和HTML代码就能理解这个道理,代码里有该有的注释:</p>
<pre>&lt;style&gt;
<span style="color: green">/* 父元素 即帖子外框 */</span>
<span style="color: red;">#papa </span>{
&nbsp; &nbsp;<span style="color: blue;">margin</span>: auto;
&nbsp; &nbsp;<span style="color: green">/* 下面两句使用网格布局快速定位子元素绝对居中 */</span>
&nbsp; &nbsp;<span style="color: blue;">display</span>: grid;
&nbsp; &nbsp;<span style="color: blue;">place-items</span>: center;
&nbsp; &nbsp;<span style="color: blue;">width</span>: 1024px;
&nbsp; &nbsp;<span style="color: blue;">height</span>: 640px;
&nbsp; &nbsp;<span style="color: blue;">background</span>: #000;
&nbsp; &nbsp;<span style="color: blue;">box-shadow</span>: 3px 3px 20px #000;
&nbsp; &nbsp;<span style="color: blue;">perspective</span>: 1000px; <span style="color: green">/* 景深设置 */</span>
&nbsp; &nbsp;<span style="color: blue;">overflow</span>: hidden; <span style="color: green">/* 不显示溢出内容 */</span>
&nbsp; &nbsp;<span style="color: blue;">position</span>: relative; <span style="color: green">/* 父元素相对定位 */</span>
}
<span style="color: green">/* 子元素 即运动对象*/</span>
<span style="color: red;">.stars </span>{
&nbsp; &nbsp;<span style="color: blue;">position</span>: absolute; <span style="color: green">/* 子元素绝对定位 */</span>
&nbsp; &nbsp;<span style="color: blue;">width</span>: 3px; <span style="color: green">/* 宽度 */</span>
&nbsp; &nbsp;<span style="color: blue;">height</span>: 3px; <span style="color: green">/* 高度 */</span>
&nbsp; &nbsp;<span style="color: blue;">border-radius</span>: 50%; <span style="color: green">/* 圆形 */</span>
&nbsp; &nbsp;<span style="color: blue;">background</span>: silver; <span style="color: green">/* 初始背景色 */</span>
&nbsp; &nbsp;<span style="color: blue;">transform-style</span>: preserve-3d; <span style="color: green">/* 以 3d 形态展现 */</span>
}
<span style="color: green">/* 关键帧动画 :恢复初始形态(旋转与3d移位)*/</span>
<span style="color: red;">@keyframes move </span>{
&nbsp; &nbsp;to { <span style="color: blue;">transform</span>: rotate(0) translate3d(0, 0, 0); }
}
&lt;/style&gt;

&lt;<span style="color:darkred">div</span> <span style="color: red">id</span><span style="color: blue">=</span><span style="color: magenta">"papa"</span>&gt;&lt;<span style="color: darkred">/div</span>&gt;
</pre>
<p>下面,也是最后一步,我们要用 JS 写若干个&nbsp;class="stars"&nbsp;的&nbsp;span&nbsp;标签,比如 500&nbsp;个。我们将在&nbsp;JS里赋予它们上面 .stars&nbsp;选择器或许包含或许不包含的属性(包含的,CSS的原始设定会被覆盖),我们用一个&nbsp;for&nbsp;语句便可完成这个工作:</p>
<pre>&lt;script&gt;
<span style="color: blue">for</span>(j=0; j&lt;500; j++) {
&nbsp; &nbsp;<span style="color: blue">let</span> ele = <span style="color: red">document</span>.createElement(<span style="color: magenta">'span'</span>);
&nbsp; &nbsp;ele.className = <span style="color: magenta">'stars'</span>;
&nbsp; &nbsp;ele.style.cssText += `
&nbsp; &nbsp;&nbsp; &nbsp;background: hsl(${<span style="color: red">Math</span>.random() * 255}, ${<span style="color: red">Math</span>.random() * 50 + 40}%,${<span style="color: red">Math</span>.random() * 70 + 20}%);
&nbsp; &nbsp;&nbsp; &nbsp;transform: rotate(${<span style="color: red">Math</span>.random() * 720}deg) translate3d(${<span style="color: red">Math</span>.random() * 500}px,${<span style="color: red">Math</span>.random() * 300}px,${<span style="color: red">Math</span>.random() * 1000}px);
&nbsp; &nbsp;&nbsp; &nbsp;animation: move 30s infinite ${-10 - <span style="color: red">Math</span>.random() * 20}s linear;
&nbsp; &nbsp;`;
&nbsp; &nbsp;papa.appendChild(ele);
}
&lt;/script&gt;
</pre>

<p>for语句中,我们创建了 500个 span&nbsp;标签并追加到 id="papa"&nbsp;的父元素中,这些 span 标签&nbsp;class&nbsp;名为&nbsp;stars,便能使用&nbsp;CSS&nbsp;选择器&nbsp;.stars&nbsp;里定义的属性,同时我们添加了新的属性,也修改了 .stars&nbsp;选择器的部分属性,通过 ele.style.cssText += `...`;&nbsp;来实现。符号 ``&nbsp;里面的内容中,我们设定了背景色&nbsp;background&nbsp;是随机的&nbsp;hsla&nbsp;值,transform&nbsp;变换则是,先随机旋转(rotate),再随机3d移位(translate3d)。每一个&nbsp;span&nbsp;标签因为随机的设置,它们的初始形态,如旋转多少度、移位到哪里,都是不同的,然后通过&nbsp;animation 调用关键帧动画&nbsp;move,加入一个延时机制,便可创建出令人惊艳的画面。效果请看二楼。</p>
<p>补充说明一下:关键帧动画中使用的是&nbsp;translate3d,其中的第三个参数针对&nbsp;Z轴,该参数随机获取,本例取值范围在 0 - 1000px&nbsp;之间,值小时对象大,值大时对象小。</p>

</div>

马黑黑 发表于 2022-11-4 20:13

<style>
#papa {
        left: -214px;
        display: grid;
        place-items: center;
        width: 1024px;
        height: 640px;
        background: #000;
        box-shadow: 3px 3px 20px #000;
        perspective: 1000px;
        overflow: hidden;
        position: relative;
        z-index: 1;
}
.stars {
        position: absolute;
        width: 3px;
        height: 3px;
        border-radius: 50%;
        background: silver;
        transform-style: preserve-3d;
}
@keyframes move {
        to { transform: rotate(0) translate3d(0, 0, 0); }
}
</style>

<div id="papa">

</div>

<script>
for(j=0; j<500; j++) {
        let ele = document.createElement('span');
        ele.className = 'stars';
        ele.style.cssText += `
                background: hsl(${Math.random() * 255}, ${Math.random() * 50 + 40}%,${Math.random() * 70 + 20}%);
                transform: rotate(${Math.random() * 720}deg) translate3d(${Math.random() * 500}px,${Math.random() * 300}px,${Math.random() * 1000}px);
                animation: move 30s infinite ${-10 - Math.random() * 20}s linear;
        `;
        papa.appendChild(ele);
}
</script>

马黑黑 发表于 2022-11-4 20:18

全部代码
<style>
#papa {
        margin: auto;
        display: grid;
        place-items: center;
        width: 1024px;
        height: 640px;
        background: #000;
        box-shadow: 3px 3px 20px #000;
        perspective: 1000px;
        overflow: hidden;
        position: relative;
        z-index: 1;
}
.stars {
        position: absolute;
        width: 3px;
        height: 3px;
        border-radius: 50%;
        background: silver;
        transform-style: preserve-3d;
}
@keyframes move {
        to { transform: rotate(0) translate3d(0, 0, 0); }
}
</style>

<div id="papa">

</div>

<script>
for(j=0; j<500; j++) {
        let ele = document.createElement('span');
        ele.className = 'stars';
        ele.style.cssText += `
                background: hsl(${Math.random() * 255}, ${Math.random() * 50 + 40}%,${Math.random() * 70 + 20}%);
                transform: rotate(${Math.random() * 720}deg) translate3d(${Math.random() * 500}px,${Math.random() * 300}px,${Math.random() * 1000}px);
                animation: move 30s infinite ${-10 - Math.random() * 20}s linear;
        `;
        papa.appendChild(ele);
}
</script>

千羽 发表于 2022-11-4 20:42

马黑黑 发表于 2022-11-4 20:13
#papa {
        left: -214px;
        display: grid;


这个效果太漂亮了,给黑黑老师点赞送花花{:4_187:}{:4_199:}

马黑黑 发表于 2022-11-4 20:58

千羽 发表于 2022-11-4 20:42
这个效果太漂亮了,给黑黑老师点赞送花花

你可以考虑用到你的帖子

千羽 发表于 2022-11-4 20:58

马黑黑 发表于 2022-11-4 20:58
你可以考虑用到你的帖子

嗯,我去收走{:4_181:}

千羽 发表于 2022-11-4 21:02

马黑黑 发表于 2022-11-4 20:58
你可以考虑用到你的帖子

谢谢黑黑老师{:4_187:}

马黑黑 发表于 2022-11-4 21:03

千羽 发表于 2022-11-4 21:02
谢谢黑黑老师

{:4_191:}

马黑黑 发表于 2022-11-4 21:04

千羽 发表于 2022-11-4 20:58
嗯,我去收走

{:4_187:}

小辣椒 发表于 2022-11-4 21:51

这个粒子效果真的美,很喜欢的,黑黑太强大了,无所不能啊{:4_178:}

马黑黑 发表于 2022-11-4 21:54

小辣椒 发表于 2022-11-4 21:51
这个粒子效果真的美,很喜欢的,黑黑太强大了,无所不能啊

这个粒子有中心,这是预设,可以局部或全部去中心化,实现方法是再在JS里随机给开每一个 span 元素left和top值,这个随机值还可以略作控制,中心化就不会那么明显

小辣椒 发表于 2022-11-4 22:00

马黑黑 发表于 2022-11-4 21:54
这个粒子有中心,这是预设,可以局部或全部去中心化,实现方法是再在JS里随机给开每一个 span 元素left和 ...

这个我还得再捣鼓捣鼓,感觉用自己帖里面还是要实践一下

马黑黑 发表于 2022-11-4 22:04

小辣椒 发表于 2022-11-4 22:00
这个我还得再捣鼓捣鼓,感觉用自己帖里面还是要实践一下

代码很完整的,只需把代码放对位置(这个不难)。它比较适合深色背景的帖子

风中飞尘 发表于 2022-11-4 22:07

这个粒子能不能修改成   跟着音乐节奏跳动而跳动 那样的话特别棒{:4_196:}

马黑黑 发表于 2022-11-4 22:11

风中飞尘 发表于 2022-11-4 22:07
这个粒子能不能修改成   跟着音乐节奏跳动而跳动 那样的话特别棒

我说过,要让音频带动粒子,需要 audio API,代码量太大太艰涩,不是非常适合做帖用。

小辣椒 发表于 2022-11-4 22:14

马黑黑 发表于 2022-11-4 22:04
代码很完整的,只需把代码放对位置(这个不难)。它比较适合深色背景的帖子

好的,我试一下

马黑黑 发表于 2022-11-4 22:14

小辣椒 发表于 2022-11-4 22:14
好的,我试一下

{:4_181:}

风中飞尘 发表于 2022-11-4 22:19

马黑黑 发表于 2022-11-4 22:11
我说过,要让音频带动粒子,需要 audio API,代码量太大太艰涩,不是非常适合做帖用。

用js HTML 调用嘛

马黑黑 发表于 2022-11-4 22:27

风中飞尘 发表于 2022-11-4 22:19
用js HTML 调用嘛

就像你发的那个音频带动频谱,如果不使用 audio API,它是不行的。音频的振幅获取即使通过audio API也十分困难,一般会考虑使用服务器版本的JS做,不过网易云音乐的地址也带动不起,需要纯粹的音频地址。总而言之,我个人觉得这个不现实。

风中飞尘 发表于 2022-11-4 22:33

马黑黑 发表于 2022-11-4 22:27
就像你发的那个音频带动频谱,如果不使用 audio API,它是不行的。音频的振幅获取即使通过audio API也十 ...
{:4_197:}
页: [1] 2
查看完整版本: CSS+JS:3d粒子一例