最近,在 CodePen 上看到这样一个非常有意思的效果:
这个效果的核心难点在于气泡的一种特殊融合效果。
其源代码在:CodePen Demo -- Goey footer,作者主要使用的是 SVG 滤镜完成的该效果,感兴趣的可以戳源码看看。
其中,要想灵活运用 SVG 中的 feGaussianBlur 滤镜还是需要有非常强大的 SVG 知识储备的。那么,仅仅使用 CSS 能否实现该效果呢?
嘿嘿,强大的 CSS 当然是可以的。本文,就将带领大家一步步使用纯 CSS,完成上述效果。
首先,如果上述效果没有气泡的融合效果,可能就仅仅是这样:
要制作这样一个效果还是比较简单的,只是代码会比较多,我们借助 SASS 预处理器即可。
假设我们有如下 HTML 结构:
<div class="g-wrap">
<div class="g-footer">
<div class="g-bubble"></div>
<div class="g-bubble"></div>
// ... 200 个 g-bubble
</div>
</div>
核心要做的,仅仅是让 200 个 .g-bubble 从底部无规律的进行向上升起的动画。
这里,就需要运用我们在 深入浅出 CSS 动画 这篇文章中所介绍的一种技巧 -- 利用 animation-duration 和 animation-delay 构建随机效果。
同一个动画,我们利用一定范围内随机的 animation-duration 和一定范围内随机的 animation-delay,可以有效的构建更为随机的动画效果,让动画更加的自然。
我们来模拟一下,如果是使用 10 个 animation-duration 和 animation-delay 都一致的圆的话,核心伪代码:
<ul>
<li></li>
<!--共 10 个...-->
<li></li>
</ul>
ul {
display: flex;
flex-wrap: nowrap;
gap: 5px;
}
li {
background: #000;
animation: move 3s infinite 1s linear;
}
@keyframes move {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(0, -100px);
}
}
这样,小球的运动会是这样的整齐划一:
要让小球的运动显得非常的随机,只需要让 animation-duration 和 animation-delay 都在一定范围内浮动即可,改造下 CSS:
@for $i from 1 to 11 {
li:nth-child(#{$i}) {
animation-duration: #{random(2000)/1000 + 2}s;
animation-delay: #{random(1000)/1000 + 1}s;
}
}
我们利用 SASS 的循环和 random() 函数,让 animation-duration 在 2-4 秒范围内随机,让 animation-delay 在 1-2 秒范围内随机,这样,我们就可以得到非常自然且不同的上升动画效果,基本不会出现重复的画面,很好的模拟了随机效果:
CodePen Demo -- 利用范围随机 animation-duration 和 animation-delay 实现随机动画效果
好,我们把上述介绍的技巧,套用到我们本文要实现的效果中去,HTML 结构再看一眼:
<div class="g-wrap">
<div class="g-footer">
<div class="g-bubble"></div>
<div class="g-bubble"></div>
// ... 200 个 g-bubble
</div>
</div>
核心的 CSS 代码:
.g-footer {
position: absolute;
bottom: 0;
left: 0;
height: 86px;
width: 100%;
background: #26b4f5;
}
@for $i from 0 through 200 {
.g-bubble:nth-child(#{$i}) {
position: absolute;
background: #26b4f5;
$width: random(100) + px;
left: #{(random(100)) + '%'};
top: #{(random(100))}px;
width: $width;
height: $width;
animation: moveToTop #{(random(2500) + 1500) / 1000}s ease-in-out -#{random(5000)/1000}s infinite;
}
}
@keyframes moveToTop {
90% {
opacity: 1;
}
100% {
opacity: .08;
transform: translate(-50%, -180px) scale(.3);
}
}
这里:
$width: random(100) + px;,随机生成不同大小的 div 圆形left: #{(random(100)) + '%'},top: #{(random(100))}px 基于父元素随机定位animation: moveToTop #{(random(2500) + 1500) / 1000}s ease-in-out -#{random(5000)/1000}s infinite,让所有 div 圆的运动都是随机的上述(1)、(2)综合结果,会生成这样一种布局,均匀分散排布的圆形:
注:这里为了方便理解,我隐藏了最外层
g-footer的颜色,并且给g-bubble添加了黑色边框
接着,如果我们替换一下 animation 语句,使用统一的动画时长,去掉负的延迟,变成 animation: moveToTop 4s ease-in-out infinite,动画就会是这样:
整体是整齐划一,没有杂乱无章的感觉的。
运用上随机效果,animation: moveToTop #{(random(2500) + 1500) / 1000}s ease-in-out -#{random(5000)/1000}s infinite,就能得到上述的,不同气泡随机上升的感觉:
接下来,也是最重要的一步,如何让气泡与气泡之间,以及气泡和底部 .g-footer 之间产生融合效果呢?
这个技巧在此前非常多篇文章中,也频繁提及过,就是利用 filter: contrast() 滤镜与 filter: blur() 滤镜。
如果你还不了解这个技巧,可以戳我的这篇文章看看:你所不知道的 CSS 滤镜技巧与细节
简述下该技巧:
单独将两个滤镜拿出来,它们的作用分别是:
filter: blur(): 给图像设置高斯模糊效果。filter: contrast(): 调整图像的对比度。但是,当他们“合体”的时候,产生了奇妙的融合现象。
仔细看两圆相交的过程,在边与边接触的时候,会产生一种边界融合的效果,通过对比度滤镜把高斯模糊的模糊边缘给干掉,利用高斯模糊实现融合效果。
基于此,我们再简单改造下我们的 CSS 代码,所需要加的代码量非常少:
.g-wrap {
background: #fff;
filter: contrast(8);
}
.g-footer {
// ... 其他保持一致
filter: blur(5px);
}
就这么简单,父容器添加白色底色以及对比度滤镜 filter: contrast(8),子容器添加 filter: blur(5px) 即可,这样,我们就能得气泡的融合效果,基本得到我们想要的效果:
但是!利用 filter: blur() 会有一个小问题。
运用了 filter: blur() 的元素,元素边缘的模糊度不够,会导致效果在边缘失真,我们仔细看看动画的边缘:
如何解决呢?也好办,在这里,我们尝试利用 backdrop-filter 去替换 filter。
两者之间的差异在于,filter 是作用于元素本身,而 backdrop-filter 是作用于元素背后的区域所覆盖的所有元素,如果你想了解更多关于 backdrop-filter 的信息,可以戳我的这篇文章:深入探讨 filter 与 backdrop-filter 的异同。
简单改造下代码,原代码:
.g-footer {
// ...
filter: blur(5px);
}
改造后的代码:
.g-footer {
// ... 去掉 filter: blur(5px)
&:before {
content: "";
position: absolute;
top: -300px;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
backdrop-filter: blur(5px);
}
}
我们通过去到原来添加在 .g-footer 上的 filter: blur(5px),通过他的伪元素,叠加一层新的元素在它本身之上,并且添加了替代的 backdrop-filter: blur(5px)。
当然,因为这里的 blur(5px) 还需要为气泡与气泡之间的融合服务,所以为了覆盖动画全区域,我们还设置了 top: -300px,扩大了它的作用范围。
最终,我们就能完美的复刻文章一开头,使用 SVG 滤镜实现的效果:
在文章中,我省去了大部分基础的 CSS 代码,完整的代码,你可以戳这里:CodePen Demo -- Bubble Rises
本文与之前的 巧用 CSS 实现酷炫的充电动画 内使用的技巧非常类似,但本文也有一些新的知识点,大家可以结合着一起看看。
好了,本文到此结束,希望对你有帮助 ?
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po