马黑黑 发表于 2022-2-2 17:21

CSS如何模拟雨丝

本帖最后由 马黑黑 于 2022-2-2 17:29 编辑 <br /><br /><style>
.papaDiv {
        margin: auto;
        position: relative;
        background: #333;
        width: 720px;
        height: 460px;
}

.rain {
        width: 1px;
        height: 8px;
        top: -5px;
        left: 100px;
        background: #eee;
        position: absolute;
        animation: rain 0.5s linear infinite;
}

@keyframes rain {
        0% { opacity:0.2; }
        100% { opacity:0.5; top:80%;}
}
</style>

<div></div><p></p><div>雨丝需要场景,这里,我们用一个偏暗色的 div&nbsp;来做呈现雨丝的舞台,这就是传说中又是经常说到的父元素:</div><div><br></div><div><div>.papaDiv {</div><div><span style="white-space: pre;">        </span>margin: auto;</div><div><span style="white-space:pre">        </span><font color="#ff0000">position: relative;</font></div><div><span style="white-space:pre">        </span>background: #333;</div><div><span style="white-space: pre;">        </span>width: 720px;</div><div><span style="white-space: pre;">        </span>height: 460px;</div><div>}</div></div><div><br></div><div>父元素用绝对定位,以便稍后,子元素的绝对定位有所依据。下一步就是制作雨丝。想象一下下雨的时候,一般的情况雨丝静态时是细长的,所以我们用1*8的、背景色接近白色的子元素来模拟雨丝静态时的样子,然后雨丝看上去像是断续的直线,这部分由&nbsp;keyframes&nbsp;来设计。我们先来制作静态状况下的雨丝:</div><div><br></div><div><div>.rain {</div><div><span style="white-space:pre">        </span>width: 1px;&nbsp;</div><div><span style="white-space:pre">        </span>height: 8px;</div><div><span style="white-space:pre">        </span>top: -5px;</div><div><span style="white-space:pre">        </span>left: 100px;</div><div><span style="white-space:pre">        </span>background: #eee;</div><div><span style="white-space:pre">        </span><font color="#ff0000">position:&nbsp;absolute;</font></div><div><span style="white-space: pre;">        </span>animation: rain 0.5s linear infinite;</div><div>}</div></div><div><br></div><div>position一定要设定,绝对定位还是相对定位根据需要设定就好。最后一句是调用我们还没有设计出来的动画,动画名称我们定义为 rain:</div><div><br></div><div><div>@keyframes rain {</div><div><span style="white-space:pre">        </span>0% { opacity:0.2; }</div><div><span style="white-space:pre">        </span>100% { opacity:0.5; top:80%;&nbsp; }</div><div>}</div></div><div><br></div><div>动画很简单:百分之零时,不透明度是0.2,百分之百时,变为0.5,也就是逐渐清晰,符合自然现象的规律。当雨丝落到父窗体80%(可调)的时候停止。其余雨通常是斜着下的,可以考虑100%时left值与初始值有所差异,这里省略掉。</div><div><br></div><div>最后是&nbsp;HTML&nbsp;代码,注意,rain&nbsp;类的 div&nbsp;要嵌套在父窗体&nbsp;papaDiv&nbsp;之内:</div><div><br></div><div><font color="#006400">&lt;div class="papaDiv"&gt;</font></div><div><font color="#006400">&nbsp; &nbsp; </font><font color="#8b0000">&lt;div class="rain"&gt;&lt;/div&gt;</font></div><div><font color="#006400">&lt;/div&gt;</font></div><div><br></div><div>效果演示:</div><div><br></div>

<div class="papaDiv">
    <div class="rain"></div>
</div>

<div><br></div><div>当然,这里我们仅仅创建了一个独立的雨点单位,生成多多的雨丝可以手动去写HTML代码的子&nbsp;div,每一个雨丝的初始 left&nbsp;值都要重新定义,比如下一个雨丝:</div><div><br></div><div>&lt;div class="rain" <font color="#ff0000">style="left: 215px;"</font>&gt;&lt;/div&gt;</div><div><br></div><div>它们这些子div必须写在&nbsp;papaDiv&nbsp;的框架之内,做&nbsp;papaDiv&nbsp;的子元素。</div><div><br></div><div>如果会JS,那就用JS生成合适数量的雨丝div,可以令JS随机产生&nbsp;left&nbsp;的起始值,这样,雨丝的出发点各不相同,得到的效果就是雨丝是分散着的、大致均匀分布的。</div>

加林森 发表于 2022-2-2 18:40

这个得好好地学习了。谢谢老黑。{:4_190:}

红影 发表于 2022-2-2 19:03

这个没有JS参与,那个《江南印记》的帖子比这个要复杂。

红影 发表于 2022-2-2 19:05

那个帖子里甚至有涟漪。

马黑黑 发表于 2022-2-2 20:21

红影 发表于 2022-2-2 19:05
那个帖子里甚至有涟漪。

涟漪就是一个一个的圈圈,懂得做雨丝,就懂得做涟漪

马黑黑 发表于 2022-2-2 20:22

红影 发表于 2022-2-2 19:03
这个没有JS参与,那个《江南印记》的帖子比这个要复杂。

复杂是从简单来的。复杂是重复的简单。

红影 发表于 2022-2-2 20:49

马黑黑 发表于 2022-2-2 20:21
涟漪就是一个一个的圈圈,懂得做雨丝,就懂得做涟漪

还得把它们组合到一起,挺不容易的{:4_187:}

红影 发表于 2022-2-2 20:50

马黑黑 发表于 2022-2-2 20:22
复杂是从简单来的。复杂是重复的简单。

嗯,先从简单的学习,是必须的。

马黑黑 发表于 2022-2-2 21:22

红影 发表于 2022-2-2 20:50
嗯,先从简单的学习,是必须的。

是的,不能一蹴而就

马黑黑 发表于 2022-2-2 21:23

红影 发表于 2022-2-2 20:49
还得把它们组合到一起,挺不容易的

组合不容易的地方是对标,我再研究如何可以对标

马黑黑 发表于 2022-2-2 23:53

本帖最后由 马黑黑 于 2022-2-3 13:21 编辑

用 JS 批量生成雨丝:

<script language="javascript">
//创建一个自定义函数 addrain() :用于批量生成雨丝
function addrain() {
      var papa = document.getElementById('papaDiv'); // 父元素变量
      for(i=0; i<50; i++) { // 循环执行 50 次
                // 新子元素创建及属性赋值
                var rain = document.createElement('div'); // 创建一个div
                var rLeft = Math.ceil(Math.random()*100); // 雨丝left随机值
                var aTime = Math.random(); // 动画运行时长 0.0-0.9
                rain.className = "rain"; // 子元素的 class 类名赋值为我在CSS创建的 .rain
                rain.style.left = rLeft + "%"; // 用随机百分比赋值给新创建的子div
                // 新子元素动画样时长:aTime
                rain.style.animation = "rain " + aTime + "s linear infinite";
                papa.appendChild(rain); // 父元素追加新的子元素
      }
}
//运行函数
addrain();

</script>


JS批量生成元素有很多方法,今天我们用的是 createElement 和 appendChild 来配合完成。

createElement 正如其单词的组合含义,其意为创建元素,通常按如下方式使用:

var rain = document.createElement("div");

rain 是我们定义的所创建的对象的变量名称,有了它我们可以在后面对要创建的对象进行相关赋值;document 是web页文档载体,创建的东西以它为依托,document.createElement("div") 指的是在web文档中创建一个 div 标签,其变量名是等号前边的 rain。

有了新创建的对象 rain,还需给它赋值,比如它的 class 名称:

rain.className = "rain";

左边的 rain 是上面创建的,className 是JS大哥称呼CSS中的 class 的方法,注意写法,n是大写的;等号后面双引号里的 rain 是我们在CSS里定义的一个类选择器 .rain 。这样,新创建的 div 就具备了 CSS 里定义的 .rain 的属性。

再比如它的 left 属性值:

rain.style.left = "40%"; // 或 "400px"

JS大哥给HTML标签定义CSS样式总是这么写的,xx.style.yy,xx 是标签对象,style 就是 CSS 样式,yy 是什么CSS属性(比如left、top、width等),等号后面给出具体的值,值要放在小角引号内。有变量的时候变量不能放在引号里,要这样表示(假设有一个变量 a ):

rain.style.left = a + "%"; // 或 a + "px";

当所有的新元素的属性都赋值完毕,我们就可以真正的将已经创建的子元素追加到父元素的子元素序列中来:

papa.appendChild(rain);

papa 是我们定义的函数里最先声明的变量,它代表雨丝所在的父元素,它追加一个儿子(append 追加,Child 儿子,注意是个大儿子虽然是后来生的,哦不,child头一个字母c要大写C),这个儿子名叫rain(rain此处是变量,不是CSS里的 .rain)。

如此辛苦才能添加一个子元素(生孩子不容易的),所以,我们将以上分析的这些放在一个 for 循环语句中执行,让它一下子生出 50 个甚至更多的孩子来。

函数设定好了,别忘了执行一次:

addrain();

这就妥了。

这里,代码量其实不多,但其中有很多JS特定的东东,包含陌生的概念和函数、方法,也许看不懂。这没关系,懂多少算多少,能够通过我的说明了解一下实现过程也很不错。

马黑黑 发表于 2022-2-2 23:55

本帖最后由 马黑黑 于 2022-2-3 13:24 编辑 <br /><br /><p>我若加入 js 代码,一楼的雨丝会如何?它不会改变,因为:<br>&nbsp;</p>

<p>父div没有id标识。papa 是通过 id 识别的。所以,HTML代码要改一下:<br>&nbsp;</p>
<p>
&lt;div <span style="color:red;">id="papaDiv"</span> class="papaDiv"&gt;<br>
&nbsp;&nbsp;&nbsp;        &lt;div class="rain"&gt;&lt;/div&gt;<br>
&lt;/div&gt;</p><p>&nbsp;</p>

<div id="papaDiv" class="papaDiv">
        <div class="rain"></div>
</div>

<script language="javascript">
//创建一个自定义函数 addrain() :用于批量生成雨丝
function addrain() {
        var papa = document.getElementById('papaDiv'); // 父元素变量
        for(i=0; i<50; i++) { // 循环执行 50 次
                // 新子元素创建及属性赋值
                var rain = document.createElement('div'); // 创建一个div
                var rLeft = Math.ceil(Math.random()*100); // 雨丝left随机值
                var aTime = Math.random(); // 动画运行时长 0.0-0.9
                rain.className = "rain"; // 子元素的 class 类名赋值为我在CSS创建的 .rain
                rain.style.left = rLeft + "%"; // 用随机百分比赋值给新创建的子div
               // 新子元素动画样时长:aTime
                rain.style.animation = "rain " + aTime + "s linear infinite";
                papa.appendChild(rain); // 父元素创建新的子元素
        }
}
//运行函数
addrain();

</script>

马黑黑 发表于 2022-2-3 00:05

上面这个 JS 设计,动画运行时长随机数我偷懒用了一个伪随机数:

var aTime = Math.random();

它能产生 0.0-0.9之间的数值,不排除0,所以上面的纷纷雨丝有可能会有非常快的

加林森 发表于 2022-2-3 11:27

这个下得好密集的。

红影 发表于 2022-2-3 13:13

马黑黑 发表于 2022-2-2 21:22
是的,不能一蹴而就

而且学了理论,还需要运用才会熟悉。

红影 发表于 2022-2-3 13:14

马黑黑 发表于 2022-2-2 21:23
组合不容易的地方是对标,我再研究如何可以对标

一个不注意,你楼下又批量生产了那么多的雨丝啊{:4_173:}

马黑黑 发表于 2022-2-3 13:15

红影 发表于 2022-2-3 13:14
一个不注意,你楼下又批量生产了那么多的雨丝啊

陆续来的,要说清楚方法和原理,一下子说完不好理解

红影 发表于 2022-2-3 15:39

马黑黑 发表于 2022-2-3 13:15
陆续来的,要说清楚方法和原理,一下子说完不好理解

如果写成rain.style.left = "400px"+ "90%";

可以这样具体值和百分比混写么,这样是不是就从400个单位到左边的90%有雨丝了?

马黑黑 发表于 2022-2-3 15:51

红影 发表于 2022-2-3 15:39
如果写成rain.style.left = "400px"+ "90%";

可以这样具体值和百分比混写么,这样是不是就从400个单位 ...

这个写法是错误的,这将到不到正确的结果。两种方法只选择一种:

rain.style.left = "400px";
rain.style.left = "90%";

css允许用 calc 来运算,特殊情形时才使用。

第二个问题:上面这个语句定义的只是一根雨丝的左边位置。每一根雨丝的位置都是随机生成的,是另外的机制。

红影 发表于 2022-2-3 16:41

马黑黑 发表于 2022-2-3 15:51
这个写法是错误的,这将到不到正确的结果。两种方法只选择一种:

rain.style.left = "400px";


哦哦,我把这个跟随机那个搞混了{:4_173:}
页: [1] 2
查看完整版本: CSS如何模拟雨丝