运气爆棚的我总是时不时地能创建出大家都喜欢的案例。SVG Lava Lamp就是其中之一——因为很多人问我关于这个灯的文字,所以我决定写这篇文章来给大家解释解释。
一眼看去,这篇教程好像会有很多很多的代码——其实不是这样的。我只是在不停地粘贴相同的代码,所以代码量会慢慢增加,看起来也就好像代码量很大了。
还有标题看起来也挺好笑的——虽然我喜欢开玩笑,但也不会影响到后边各小节的内容,它们其实还是挺简单的。如果觉得它们倒了你的胃口,或者你的母语不是英语的话(无法理解我),我还是赶紧先在这里道个歉吧哈哈。
如果你在找Adobe Illustrator这款软件(或相关链接)的话,可以戳这里下载。
希望这听起来不会很随意,在制作这个案例的时候并没有考虑那么多的东西——可能就是2到3个小时,部分原因是我有Sara Farnsworth的非常棒的shot作为参考——它非常棒而且给了我很多灵感~
闲聊到此为止
好了我不继续闲聊了(:зゝ∠)
创建这个动画的主要难点在于浏览器之外的绘图程序。实际的JavaScript动画大约只有15-20行代码。
你需要一个像Adobe Illustrator (AI)这样的矢量绘图软件。但是它实在是贵到令人发指!!所以我们还有其他的选择,如Sketch[$99]和InkScape[免费!]。但是我用的是AI,因为我已经用习惯了╮(╯▽╰)╭。
除此之外我们还需要GSAP的TweenMax库,这个倒是免费的。
好剑出鞘!!
首先,创建一个600x600
的画板。我也不知道为什么我总是用这个尺寸,不过对我来说正好合适。
现在来绘制玻璃瓶的形状——我们会使用这个形状作为实际的玻璃以及光斑的遮罩(实际上是clipPath,它和SVG中的mask遮罩还是有一些不同的)。玻璃的颜色并不要紧,因为我们会在后边的代码中删掉它。后面再详细介绍。
现在绘制顶部和底部的部分——注意到在顶部和底部,都有一个非常暗的从橙色到黑色的渐变。这可以创建一个熔岩光溢出的错觉。
我们还需要绘制所有的蜡光斑,然后给它们填充一个径向渐变——只需要画四到五个不同尺寸和形状的就ok。使用椭圆工具先画出一个圆,然后应用一个AI通道滤镜(Filter > Warp > Arc Lower
),然后做一些弯曲和变形的设置(记得打开预览哟~)。
一旦画好了光斑,然后确保较暗的渐变的那部分比较靠近顶部——因为这个灯的光源是在下面的。现在把它们都放置在熔岩灯的顶部周围(如果你见过真正的熔岩灯,就会注意到光斑是在顶部的牙轮里面消失的)。
不要忘了还要画一个更大的更平的光斑放置在底部,这个光斑的顶部只比顶部的碗座高出一点点。虽然这不是一个真正的熔岩灯,但是所有的蜡融化和诗意的漂浮有助于粘稠的效果,所以我们添加SVG模糊和颜色矩阵滤镜,结合起来才创建出粘稠的效果。
噢我差点忘了!我画了一个桌子(底部的黑色矩形)在那里——否则它看起来就像是漂浮在半空中的。
最后我做了一个带径向渐变的矩形,放置在最底层,作为一个背景阴影。我一开始尝试过在玻璃上应用一个SVG glow滤镜,但是效果非常糟糕,而且从形状上看并没有得到我想要的效果,所以这是一套美观合适的解决方案。
现在,如果你碰巧参加了我九月份在英国Brighton的“为什么要有创意的原因”的座谈会,首先感谢你的到来——会议非常好玩!你可能还记得我一直在强调一个非常重要的技巧,在从AI的画板上复制和粘贴你的图形到一个文本编辑器中(或CodePen等等)的时候。我会在这里再次强调,因为这真的非常重要。
一个非常有用的技巧
你可以在AI中把你的SVG保存成.svg
格式的文件,但是有一点非常烦人的就是它会输出所有图层,不论它是否可见。它还倾向于生成内联环路,这点我非常不喜欢。
通常我都是挑选好需要的层,然后把它们复制粘贴到我的文本编辑器中。这种方法存在的问题是,当你选择好然后复制粘贴到一个编辑器中时,你粘贴的是一整个SVG的高度和宽度,还是你选中的图层的高度和宽度呢。
当你在AI中选中元素,然后复制粘贴到编辑器中,你粘贴的是一整个SVG的高度和宽度,还是你选中的图层的高度和宽度呢。
也就是说,如果你的玻璃灯图片是在600x600
尺寸的画板上,包括顶部和底部的图像,你想要创建一个600x600
的SVG,还要让这些元素准确地放置在你希望它出现的位置,你可能会想通过选中这些元素,并将其复制/粘贴到编辑器中就可以得到你想要的结果。但是事实并非如此,因为它并不知道自己粘贴的上下文(画板);所以它选择的是对应图层的高度和宽度,并将其作为结果SVG的高度和宽度。
注意变换面板——它显示了你选中图层的宽度是131.304px
,高度是304px
。当你将其复制粘贴到一个HTML页面中时,它的SVG如下:
(我刚刚意识到我没有画好——底座顶部的线竟然没有对齐!!!)
高亮显示SVG的宽度(131.3
)和高度(304
)——生成的SVG和选中图层是相同的尺寸,也就是说你失去了600x600
的画板,它们现在并没有按照我们希望的放置在中心的位置。
在AI中画一个和你的画板一样尺寸的矩形,然后在将画板上的内容复制到编辑器时,和其它的元素一起选中它。
这个简单的解决方案(我知道能够写成一个教程的东西从来都不是简单的,但是在这种特定情况下,它真的很简单!)就是在AI中绘制一个矩形,和你的画板一样的尺寸,然后每次复制内容到编辑器时一起选中它。从现在起,我把它当做一个“上下文”图层。你可以在后面从SVG代码中丢弃这个上下文图层,但是在复制/粘贴的过程中这真的是必不可少的,这样生成的SVG才可以保持600x600
的画板尺寸(因为上下文图层和画板是一样的大小)。对吧?
所以现在是...
...然后在HTML中生成...
现在看起来好像好点了。
所以,现在你需要添加蜡光斑,你可以把它们全部选中,然后添加上下文图层(保持按住shift
键然后选中它)——这样它们才可以保留在正确的位置。
我习惯使用Sublime Text作为“中间人”来整理我的SVG,然后挑选我需要的部分。这不是绝对必要的,但是我喜欢Sublime的“查找/替换/正则表达式”功能,所以用来帮我执行清理任务是非常合适的。你可以很方便地把它们都粘贴到CodePen的HTML面板中。
有关图层的一个简短的说明——我给所有图层都命名了,即使我不打算给所有图层都添加动画。图层名在SVG中会变成它们自身的id
(尽管有AI自己加上的恼人的数字和下划线╭(╯^╰)╮)。给图层命名使得它们之后放到在页面中更容易被识别。
正如我上面提到的,AI会给每个图层添加id——如果是添加类名的话就更好一些了——这样的话你就可以有几个通过类名联系起来的图层了。尽管这是一个方法,在我前面提到的座谈会上,我提到了一个点,把SVG数据粘贴到sublime中,然后修改所有的id=
变成class=
。这其实有一点危险,因为引用的渐变、滤镜、clipPath(还有很多其它的内容)都需要通过id
来索引,所以我现在暂时没有把id
换成class
。如果我真的需要使用class
给元素分组,我会加上class
名,但是还是保留id
。
制作过程,用大白话好好讲解
我们已经准备好要把图形放到页面上了。开始前,我想要用简单的英语解释一下动画的工作原理。我在创建任何东西或者写任何代码之前,都会做很多准备工作——我会先自己弄清楚视觉上的效果要如何用技术实现。
- 使用玻璃(主灯体)有两个用途。首先,我们在视觉上将它显示为一个低透明度的图形(这样看起来才像玻璃)。接着我们使用相同的图形作为包裹后面那组蜡光斑的
clipPath
。 - 我们会把蜡光斑组成一组,然后应用几个滤镜(这样可以应用于组中的所有成员上)。丑丑的粘稠效果使用的是高斯模糊滤镜,
alpha
对比度提升到使用颜色矩阵滤镜(我不会去考虑粘稠效果太多的细节,因为这是在这篇文章范围之外的内容,但是这里有篇文章解释得非常好,使用了几个GIF图片)。 - 我们给光斑添加动画,使得它可以上下循环(通过一个
TweenMax
实例),每个光斑都有一个随机时长(在特定参数内)。在重复它们自身的循环之前,都有一段随机等待时间。 - 我们给主要的
TimelineMax
实例添加TweenMax
补间,但是让它们在不同的时间开始。 - 最后我们设置(
TimelineMax.seek(100);
),调到主时间轴约100s
的位置,使得熔岩灯在每次加载的时候都是进行时的状态。
复制、粘贴、整理
最后我们可以把它从AI中导出,然后放到文本编辑器中来整理。
我们可以选择我们需要的图层,然后把它们复制过来。这块是没有问题的,除了最后你会得到大量的代码段,而且看起来都非常相似,而且可能很快会变得非常混乱,如果你不是一次性完成的话。我习惯复制一段一段的内容,然后再把内容整合到一起。
所以,首先把所有图层都隐藏。然后显示bg
层,选中它(确保它是放在最底层,以显示实际的图形层)——这是一个带有渐变的矩形,放置在熔岩灯的后面,处在SVG文件的最底层。在这里我们不需要选中600X600
的上下文图层(用于保持SVG的尺寸),因为这个bg
图层的尺寸就是600X600
。现在把它复制到文本编辑器中,结果如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
</defs>
<radialGradient id="bg_3_" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<rect id="bg_2_" fill="url(#bg_3_)" width="600" height="600"/>
</svg>
这样我们的第一次复制/粘贴就完成了,创建了一个600X600
的SVG文件,因为我们粘贴的图形就是600X600大小的。现在开始我们给这个SVG添加新的图形。
AI提供的id名bg_2
真的非常难看而且笨拙。把_2
删掉。它还会生成id为id_3
的渐变。我们把它修改成像bgGrad
这样可读性强的名字——我们还需要把<rect>
的填充属性改为fill="url(#bgGrad)"
。
我希望保留<defs></defs>
标签中定义的渐变、滤镜、clipPaths
和遮罩。这里通常用来防止那些暂时不让它可视化的内容。所以我们把渐变标签移动一下——大概像这样:
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
</svg>
好的我们赢啦(这听起来好像有点自满哈哈,sorry)。
现在在codepen中创建一个案例,然后把这段代码从文本编辑器中复制到HTML面板中。这里我假设你是有自己的codepen账号的——如果你没有的话,我可能就不想跟你做朋友了。
我不会给你展示这看起来是如何的,因为这和最后的代码片段是一样的。
现在回到AI里,隐藏bg
图层——我们接下来都不需要它了。尽管我们现在需要一个600X600
的上下文图层(就是那个可怕的紫色图层)。我前面提到这个图层非常非常重要了吧?什么?没有?蹲墙角反省去,都不好好看文章!
我们接下来添加玻璃。选中glassShape
图层,记得一起选中上下文图层。然后把它复制/粘贴到sublime中。不要担心粘贴过去的最后一项是啥——我们使用编辑器只是作为一个中间件。
所以它现在是这样的:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
</defs>
<rect id="context_1_" fill="#523CBF" width="600" height="600"/>
<path id="glassShape_1_" fill="#F21458" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</svg>
把glassShape
上的_1
删掉,把fill
属性也删掉(我后面会解释为什么)。现在只复制路径数据到案例中——像这样选中:
<path id="glassShape" fill="#F21458" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
你可能还记得,我们有两处地方要使用这个——玻璃图形和clipPath
(给蜡光斑添加遮罩)。
所以在codepen中我们需要在<defs>
标签内添加一个<clipPath>
标签,然后把这个玻璃图形放进去。我们还需要给clipPath
一个id
(起名glassMask
)。你的codepen里HTML面板的SVG代码应该如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
</svg>
在案例的预览区域是看不到任何内容的,除了背景的渐变。这是因为我们刚才把玻璃图形添加到<defs>
中了,这块是不可见的。为了使glassShape
可见,我们使用一个<use>
标签把它添加到渐变背景的下方。我们把opacity
也调低了,这样背景可以穿透显示。
这里还有一点值得一提的是,尽管glassShape
已经放置在<clipPath>
标签中了,我们还是可以在其它地方引用,让它多次出场都是没问题的。
现在我们的代码如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
<use xlink:href="#glassShape" fill="#EB7619" opacity="0.1"/>
</svg>
注意我给<use>
实例添加了fill="#EB7619"
。
我们之前把初始的glassShape
上的fill
属性删除了,这样我们可以在<use>
实例中添加这个样式。如果我们保留了初始glassShape
的fill
属性,我们就不能在后面的<use>
实例中重写这个属性了。
现在你的预览面板中的玻璃和背景应该显示如下:
还醒着吗朋友?对的,有人开了扇窗。
接下来我们把桌子摆上,还有熔岩灯的底部和顶部。选中它们,记得包括上下文图层,然后把它们复制到你的文本编辑器中。
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
</defs>
<rect id="context_1_" fill="#523CBF" width="600" height="600"/>
<linearGradient id="lampTop_2_" gradientUnits="userSpaceOnUse" x1="292" y1="135" x2="292" y2="174">
<stop offset="1.530612e-002" style="stop-color:#000000"/>
<stop offset="0.233" style="stop-color:#050202"/>
<stop offset="0.4808" style="stop-color:#120706"/>
<stop offset="0.7421" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<polygon id="lampTop_1_" fill="url(#lampTop_2_)" points="269,135 262,174 322,174 316,135 "/>
<linearGradient id="lampBot_2_" gradientUnits="userSpaceOnUse" x1="292.375" y1="470" x2="292.375" y2="379">
<stop offset="5.102041e-003" style="stop-color:#000000"/>
<stop offset="0.2251" style="stop-color:#050202"/>
<stop offset="0.4754" style="stop-color:#120706"/>
<stop offset="0.7394" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<path id="lampBot_1_" fill="url(#lampBot_2_)" d="M226.8,379c2.6,43,23.9,54.6,28.3,60.2c3.3,5.4-10,30.8-10,30.8h95.5
c0,0-16.5-25.1-14.5-30.8s26-15.2,32-60.2C328,379,240.3,379,226.8,379z"/>
<rect id="tableTop_1_" y="470" width="600" height="130"/>
</svg>
再次,我们把lampTop
、lampBot
和tableTop
里的_1
都删掉。不要担心重命名渐变引用(例如:fill="url(#lampBot_2_)"
)——重命名渐变和fill
引用,可以使它工作得更好。
现在,把渐变标签复制/粘贴到<defs>
标签中,在codepen的HTML面板。代码如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
<linearGradient id="lampTop_2_" gradientUnits="userSpaceOnUse" x1="292" y1="135" x2="292" y2="174">
<stop offset="1.530612e-002" style="stop-color:#000000"/>
<stop offset="0.233" style="stop-color:#050202"/>
<stop offset="0.4808" style="stop-color:#120706"/>
<stop offset="0.7421" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<linearGradient id="lampBot_2_" gradientUnits="userSpaceOnUse" x1="292.375" y1="470" x2="292.375" y2="379">
<stop offset="5.102041e-003" style="stop-color:#000000"/>
<stop offset="0.2251" style="stop-color:#050202"/>
<stop offset="0.4754" style="stop-color:#120706"/>
<stop offset="0.7394" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
<use xlink:href="#glassShape" fill="#EB7619" opacity="0.1"/>
</svg>
现在复制lampTop
、lampBot
和tableTop
,然后把它们粘贴到玻璃图形的<use>
标签的后面。
代码如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
<linearGradient id="lampTop_2_" gradientUnits="userSpaceOnUse" x1="292" y1="135" x2="292" y2="174">
<stop offset="1.530612e-002" style="stop-color:#000000"/>
<stop offset="0.233" style="stop-color:#050202"/>
<stop offset="0.4808" style="stop-color:#120706"/>
<stop offset="0.7421" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<linearGradient id="lampBot_2_" gradientUnits="userSpaceOnUse" x1="292.375" y1="470" x2="292.375" y2="379">
<stop offset="5.102041e-003" style="stop-color:#000000"/>
<stop offset="0.2251" style="stop-color:#050202"/>
<stop offset="0.4754" style="stop-color:#120706"/>
<stop offset="0.7394" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
<use xlink:href="#glassShape" fill="#EB7619" opacity="0.1"/>
<polygon id="lampTop" fill="url(#lampTop_2_)" points="269,135 262,174 322,174 316,135 "/>
<path id="lampBot" fill="url(#lampBot_2_)" d="M226.8,379c2.6,43,23.9,54.6,28.3,60.2c3.3,5.4-10,30.8-10,30.8h95.5
c0,0-16.5-25.1-14.5-30.8s26-15.2,32-60.2C328,379,240.3,379,226.8,379z"/>
<rect id="tableTop" y="470" width="600" height="130"/>
</svg>
你的预览面板展示的内容应该是长这样的:
终于论到光斑了!
回到AI,隐藏我们刚才复制过的图层(除了上下文图层)。
显示所有蜡光斑图层,包括底部那个(botBlob
),选中它们包括上下文图层。
把它们复制/粘贴到你的中间件编辑器中。如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
</defs>
<rect id="context_1_" fill="#523CBF" width="600" height="600"/>
<radialGradient id="blob0_2_" cx="292" cy="171.5" r="56.5354" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<path id="blob0_1_" fill="url(#blob0_2_)" d="M326.2,149.5c-5,19.2-21.4,29.2-37.8,26.6c-16.5-2.9-33.4-12.9-37.1-26.6
c-3.8-13.6,12.5-32.1,37.8-34.9C314.4,111.8,331.3,130.4,326.2,149.5z"/>
<radialGradient id="blob1_2_" cx="297" cy="167.5" r="37.2156" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<path id="blob1_1_" fill="url(#blob1_2_)" d="M320.5,146.4c-4.4,10.1-16.4,20.2-26.8,25.3c-10.4,5.2-22.4-2.9-26.8-15.2
c-4.4-11.6,7.6-20.4,26.8-25.3C312.9,126.3,324.9,135.6,320.5,146.4z"/>
<radialGradient id="blob2_2_" cx="294" cy="157" r="23" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<path id="blob2_1_" fill="url(#blob2_2_)" d="M278,147.7c2.7-7.1,9.4-15.7,15.4-16.4c5.9-0.4,12.6,8.5,15.4,16.9
c2.7,8.4-4.2,14.9-15.4,14.2C282.2,161.5,275.3,154.8,278,147.7z"/>
<radialGradient id="botBlob_2_" cx="284.5" cy="421.5" r="53.521" gradientTransform="matrix(-2.802637e-002 -0.9996 5.9976 -0.1682 -2235.533 776.7669)" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<path id="botBlob_1_" fill="url(#botBlob_2_)" d="M354,381.2c6.8,3.4,5.4,7.4-5.6,10.4c-10.7,3.1-31.1,5.1-54.4,8.4
c-23.3,3.3-43.7,0.8-54.4-2.4c-11-3.4-12.4-7.6-5.6-13.8c6.8-7,18.9-14.6,29.6-17.4c11-3.3,20.6-1.8,30.4-1.4
c9.8,0.4,19.4,5.1,30.4,8.3C335.1,376.8,347.2,378.6,354,381.2z"/>
<radialGradient id="blob3_2_" cx="291.9382" cy="167.4587" r="41.0767" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<path id="blob3_1_" fill="url(#blob3_2_)" d="M312.7,147.3c-2.1,16.4-15.3,27.2-23.2,25.3c-8.1-1.8-12.6-13-14.8-24.9
c-1.9-11.8,2.7-22.7,14.8-25.3C301.5,119.6,314.7,130.8,312.7,147.3z"/>
<radialGradient id="blob4_2_" cx="306.5" cy="155" r="14.109" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<path id="blob4_1_" fill="url(#blob4_2_)" d="M317.8,147.4c-1,8.2-9.8,10.3-13.8,9.3c-4-0.9-6.5-3-7.6-8.9c-1-5.9,2.3-8.5,8.4-9.8
C310.8,136.6,318.8,139.1,317.8,147.4z"/>
</svg>
天呐!乱成狗了!
好吧我们需要把它整理一下。先把每条路径的id中的_1
删掉(例如:把<path id="blob4_1_"
变成<path id="blob4"
)。
然后,和之前一样,选择所有渐变标签,复制/粘贴到HTML面板的<defs>
标签内。不需要给它们的id重命名和fill
引用。
接下来选择光斑路径(应为六个),然后复制/粘贴到codepen中的HTML面板,放置在最后的路径下方(应该是tableTop
矩形)。
这块真的很无聊,但愿你没有精神崩溃,完成的代码应该如下所示:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
<!-- LAMP GRADIENTS-->
<linearGradient id="lampTop_2_" gradientUnits="userSpaceOnUse" x1="292" y1="135" x2="292" y2="174">
<stop offset="1.530612e-002" style="stop-color:#000000"/>
<stop offset="0.233" style="stop-color:#050202"/>
<stop offset="0.4808" style="stop-color:#120706"/>
<stop offset="0.7421" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<linearGradient id="lampBot_2_" gradientUnits="userSpaceOnUse" x1="292.375" y1="470" x2="292.375" y2="379">
<stop offset="5.102041e-003" style="stop-color:#000000"/>
<stop offset="0.2251" style="stop-color:#050202"/>
<stop offset="0.4754" style="stop-color:#120706"/>
<stop offset="0.7394" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<!--END LAMP GRADIENTS-->
<!-- BLOB GRADIENTS -->
<radialGradient id="blob0_2_" cx="292" cy="171.5" r="56.5354" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob1_2_" cx="297" cy="167.5" r="37.2156" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob2_2_" cx="294" cy="157" r="23" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="botBlob_2_" cx="284.5" cy="421.5" r="53.521" gradientTransform="matrix(-2.802637e-002 -0.9996 5.9976 -0.1682 -2235.533 776.7669)" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob3_2_" cx="291.9382" cy="167.4587" r="41.0767" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob4_2_" cx="306.5" cy="155" r="14.109" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<!-- END BLOB GRADIENTS-->
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
<use xlink:href="#glassShape" fill="#EB7619" opacity="0.1"/>
<polygon id="lampTop" fill="url(#lampTop_2_)" points="269,135 262,174 322,174 316,135 "/>
<path id="lampBot" fill="url(#lampBot_2_)" d="M226.8,379c2.6,43,23.9,54.6,28.3,60.2c3.3,5.4-10,30.8-10,30.8h95.5
c0,0-16.5-25.1-14.5-30.8s26-15.2,32-60.2C328,379,240.3,379,226.8,379z"/>
<rect id="tableTop" y="470" width="600" height="130"/>
<path id="blob0" fill="url(#blob0_2_)" d="M326.2,149.5c-5,19.2-21.4,29.2-37.8,26.6c-16.5-2.9-33.4-12.9-37.1-26.6
c-3.8-13.6,12.5-32.1,37.8-34.9C314.4,111.8,331.3,130.4,326.2,149.5z"/>
<path id="blob1" fill="url(#blob1_2_)" d="M320.5,146.4c-4.4,10.1-16.4,20.2-26.8,25.3c-10.4,5.2-22.4-2.9-26.8-15.2
c-4.4-11.6,7.6-20.4,26.8-25.3C312.9,126.3,324.9,135.6,320.5,146.4z"/>
<path id="blob2" fill="url(#blob2_2_)" d="M278,147.7c2.7-7.1,9.4-15.7,15.4-16.4c5.9-0.4,12.6,8.5,15.4,16.9
c2.7,8.4-4.2,14.9-15.4,14.2C282.2,161.5,275.3,154.8,278,147.7z"/>
<path id="botBlob" fill="url(#botBlob_2_)" d="M354,381.2c6.8,3.4,5.4,7.4-5.6,10.4c-10.7,3.1-31.1,5.1-54.4,8.4
c-23.3,3.3-43.7,0.8-54.4-2.4c-11-3.4-12.4-7.6-5.6-13.8c6.8-7,18.9-14.6,29.6-17.4c11-3.3,20.6-1.8,30.4-1.4
c9.8,0.4,19.4,5.1,30.4,8.3C335.1,376.8,347.2,378.6,354,381.2z"/>
<path id="blob3" fill="url(#blob3_2_)" d="M312.7,147.3c-2.1,16.4-15.3,27.2-23.2,25.3c-8.1-1.8-12.6-13-14.8-24.9
c-1.9-11.8,2.7-22.7,14.8-25.3C301.5,119.6,314.7,130.8,312.7,147.3z"/>
<path id="blob4" fill="url(#blob4_2_)" d="M317.8,147.4c-1,8.2-9.8,10.3-13.8,9.3c-4-0.9-6.5-3-7.6-8.9c-1-5.9,2.3-8.5,8.4-9.8
C310.8,136.6,318.8,139.1,317.8,147.4z"/>
</svg>
注意我刚才在渐变块之间的<defs>
添加了注释,来解释谁引用了谁。
你的codepen预览面板应该如下所示——如果它正常的话:
给光斑分组、添加遮罩
还记得我们把glassShape
放到clipPath
中了吗?好了我们现在要使用它来裁剪所有的光斑,这样它们看起来就是在熔岩灯内的,但是首先我们需要把所有的光斑放到一组。这样我们就可以一次性地裁剪整个分组了。
所以,在codepen中,找到id
为blob0
的路径,在它上面添加一个<g>
标签。
找到最后一个光斑(blob4
),然后添加一个闭合标签</g>
。这样给光斑分组就完成啦。
现在回到开始的那个<g>
,然后添加裁剪路径属性,如下:
<g clip-path="url(#glassMask)">
该裁剪路径引用了我们之前在<defs>
中写的<clipPath>
标签。
你在codepen面板中的代码应该如下:
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
<!-- LAMP GRADIENTS-->
<linearGradient id="lampTop_2_" gradientUnits="userSpaceOnUse" x1="292" y1="135" x2="292" y2="174">
<stop offset="1.530612e-002" style="stop-color:#000000"/>
<stop offset="0.233" style="stop-color:#050202"/>
<stop offset="0.4808" style="stop-color:#120706"/>
<stop offset="0.7421" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<linearGradient id="lampBot_2_" gradientUnits="userSpaceOnUse" x1="292.375" y1="470" x2="292.375" y2="379">
<stop offset="5.102041e-003" style="stop-color:#000000"/>
<stop offset="0.2251" style="stop-color:#050202"/>
<stop offset="0.4754" style="stop-color:#120706"/>
<stop offset="0.7394" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<!--END LAMP GRADIENTS-->
<!-- BLOB GRADIENTS -->
<radialGradient id="blob0_2_" cx="292" cy="171.5" r="56.5354" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob1_2_" cx="297" cy="167.5" r="37.2156" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob2_2_" cx="294" cy="157" r="23" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="botBlob_2_" cx="284.5" cy="421.5" r="53.521" gradientTransform="matrix(-2.802637e-002 -0.9996 5.9976 -0.1682 -2235.533 776.7669)" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob3_2_" cx="291.9382" cy="167.4587" r="41.0767" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob4_2_" cx="306.5" cy="155" r="14.109" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<!-- END BLOB GRADIENTS-->
</defs>
<rect id="bg" fill="url(#bgGrad)" width="600" height="600"/>
<use xlink:href="#glassShape" fill="#EB7619" opacity="0.1"/>
<polygon id="lampTop" fill="url(#lampTop_2_)" points="269,135 262,174 322,174 316,135 "/>
<path id="lampBot" fill="url(#lampBot_2_)" d="M226.8,379c2.6,43,23.9,54.6,28.3,60.2c3.3,5.4-10,30.8-10,30.8h95.5
c0,0-16.5-25.1-14.5-30.8s26-15.2,32-60.2C328,379,240.3,379,226.8,379z"/>
<rect id="tableTop" y="470" width="600" height="130"/>
<g clip-path="url(#glassMask)">
<path id="blob0" fill="url(#blob0_2_)" d="M326.2,149.5c-5,19.2-21.4,29.2-37.8,26.6c-16.5-2.9-33.4-12.9-37.1-26.6
c-3.8-13.6,12.5-32.1,37.8-34.9C314.4,111.8,331.3,130.4,326.2,149.5z"/>
<path id="blob1" fill="url(#blob1_2_)" d="M320.5,146.4c-4.4,10.1-16.4,20.2-26.8,25.3c-10.4,5.2-22.4-2.9-26.8-15.2
c-4.4-11.6,7.6-20.4,26.8-25.3C312.9,126.3,324.9,135.6,320.5,146.4z"/>
<path id="blob2" fill="url(#blob2_2_)" d="M278,147.7c2.7-7.1,9.4-15.7,15.4-16.4c5.9-0.4,12.6,8.5,15.4,16.9
c2.7,8.4-4.2,14.9-15.4,14.2C282.2,161.5,275.3,154.8,278,147.7z"/>
<path id="botBlob" fill="url(#botBlob_2_)" d="M354,381.2c6.8,3.4,5.4,7.4-5.6,10.4c-10.7,3.1-31.1,5.1-54.4,8.4
c-23.3,3.3-43.7,0.8-54.4-2.4c-11-3.4-12.4-7.6-5.6-13.8c6.8-7,18.9-14.6,29.6-17.4c11-3.3,20.6-1.8,30.4-1.4
c9.8,0.4,19.4,5.1,30.4,8.3C335.1,376.8,347.2,378.6,354,381.2z"/>
<path id="blob3" fill="url(#blob3_2_)" d="M312.7,147.3c-2.1,16.4-15.3,27.2-23.2,25.3c-8.1-1.8-12.6-13-14.8-24.9
c-1.9-11.8,2.7-22.7,14.8-25.3C301.5,119.6,314.7,130.8,312.7,147.3z"/>
<path id="blob4" fill="url(#blob4_2_)" d="M317.8,147.4c-1,8.2-9.8,10.3-13.8,9.3c-4-0.9-6.5-3-7.6-8.9c-1-5.9,2.3-8.5,8.4-9.8
C310.8,136.6,318.8,139.1,317.8,147.4z"/>
</g>
</svg>
你的codepen预览面板加上裁剪的光斑之后,现在应该是长这样的:
为了创建粘稠效果的滤镜,需要添加一段JS。之后,我们会重新检查一下SVG代码,
老大,是时候让我的光斑动起来了
(这些标题真是越来越接奇怪了(:зゝ∠))
现在是时候写一些实际的JS代码了。我们会使用到GreenSock (GSAP) TweenMax库,不仅是因为它有我们需要的所有内容,如TimelineMax,还因为它真的非常棒~简单粗暴。
在codepen的JS面板中,点击那个小齿轮图标,如果你比较懒的话,可以直接从Quick Add下拉菜单中选择添加。唉,这是TweenMax(1.16.1)的旧版本了,虽然用起来完全没有问题,不过我比较喜欢追求更新到最新最新的东西,所以我建议粘贴下面的这个最新版本:
https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js
JS设置面板如下所示:
最后的JS代码
我们将要写的代码真的是非常非常的简短——大概20
行。我把它们都贴上来,然后一行一行来讲解。
function randomBetween(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
var tl = new TimelineMax();
for(var i = 0; i < 5; i++){
var t = TweenMax.to(document.querySelector('#blob' + i), randomBetween(14, 50), {
y:260,
repeat:-1,
repeatDelay:randomBetween(1, 3),
yoyo:true,
ease:Linear.easeNone
})
tl.add(t, (i+1)/0.6)
}
tl.seek(100);
JS代码讲解
function randomBetween(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
所以首先,我们要写的是一个randomBetween
函数,用于生成随机时间。传入一个最小值和最大值,然后返回它们之间的随机值。我们使用这个函数来添加一些随机的持续时间、重复延迟。
var tl = new TimelineMax();
接下来是GSAP的TimelineMax
实例。这个时间轴是我们给每个光斑添加的单独的TweenMax补间。
for(var i = 0; i < 5; i++){
var t = TweenMax.to(document.querySelector('#blob' + i), randomBetween(14, 50), {
y:260,
repeat:-1,
repeatDelay:randomBetween(1, 3),
yoyo:true,
ease:Linear.easeNone
})
tl.add(t, (i+1)/0.6)
}
tl.seek(100);
在这里我们遍历这五个光斑(不包括底部的botBlob
,因为这个是不移动的,就固定在底部),创建五个TweenMax实例,使用document.querySelector
来获得每个光斑的id引用。
y:260
告诉每个光斑在Y轴方向移动到260的位置(即,向下移动)。
这凸显了关于GSAP的一个非常重要的点,它处理SVG路径的初始X
、Y
位置的方式。就GSAP而言,当你让一条路径从它的初始位置移动(即从AI中复制过来,粘贴的位置),它将会默认X
、Y
的位置为(0,0
),不论它是处在SVG画布的哪个位置。所以尽管光斑看起来是,X
差不多为250
,Y
差不多为120
,它们都会被认为是在(0,0
)的位置。这也就是说每个光斑都会相对它的初始粘贴位置向下移260px
。
GSAP默认路径的
X
和Y
的位置为(0,0
),不论它是显示在SVG画布上的哪个位置。
在该补间,我们也使用了repeat:-1
来产生永动的up and down动画,我们还控制了每次重复之间的延迟。这是另一个随机值repeatDelay:randomBetween(1, 3)
。我们加入了yoyo:true
,这样它可以向下、然后向上、然后向下、然后向上,像一个悠悠球,而不是下到260
的位置,然后跳回它的初始位置,然后又下去了。
最后我们使用了一个linear ease(不是ease in或者ease out),因为这看起来更自然。
在循环中我们还是给主时间轴TimelineMax实例(t1
)添加了TweenMax补间实例(t
),每个实例都按时添加了一个相等的距离,除了时间轴。
时间轴现在是无限长的,会循环重复到天荒地老。如果你在时间轴的起点处开始,它会需要一小会时间来让每个光斑开始移动,因为光斑并没有被告知要在同一时间都飘起来。它们的起始时间是错开的。
所以为了解决这个问题,我们告知时间轴一开始就跳转到约100s
的地方,这样就确保了所有的光斑都是移动进行时:
tl.seek(100);
以上就是需要的所有内容了。你的pen应该是如下所示的(希望没有出错):
给我点粘稠感啊!夫人!现在就要!
当你制作lego小汽车的时候,指导书总是会告诉你要把车轮留到最后。我偷用了这个想法,只是把“轮子”换成“粘稠”。
在codepen的HTML面板中,粘贴如下<filter>
标签的内容到<defs>
标签中(哪个位置随便你)。
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 21 -9" result="cm" />
</filter>
在我们把它应用到光斑小分组之前,这都是看不到的。找一下包裹光斑小分队的<g>
标签在哪里,给它添加如下的属性。
filter="url(#goo)"
现在你的标签应该看起来是长这样的:
<g clip-path="url(#glassMask)" filter="url(#goo)">
你的熔岩灯现在应该是有光斑的啦。
最后的SVG代码,臃肿肥胖的一大块,噢~
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<defs>
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 21 -9" result="cm" />
</filter>
<clipPath id="glassMask">
<path id="glassShape" d="M262,174h60l33.5,182.3c0,0,2.7,12.8,2.5,22.8c-7.5,0-131,0-131,0s-0.7-9.3,0-18
C227.6,352.9,262,174,262,174z"/>
</clipPath>
<radialGradient id="bgGrad" cx="300" cy="300" r="300" gradientUnits="userSpaceOnUse">
<stop offset="7.142857e-002" style="stop-color:#471A19"/>
<stop offset="0.3107" style="stop-color:#290F0E"/>
<stop offset="0.553" style="stop-color:#120706"/>
<stop offset="0.7828" style="stop-color:#050202"/>
<stop offset="0.9847" style="stop-color:#000000"/>
</radialGradient>
<radialGradient id="blob3Grad" cx="291.9382" cy="167.4587" r="41.0767" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="botBlob" cx="284.5" cy="421.5" r="53.521" gradientTransform="matrix(-2.802637e-002 -0.9996 5.9976 -0.1682 -2235.533 776.7669)" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob2_2_" cx="294" cy="157" r="23" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob1_2_" cx="297" cy="167.5" r="37.2156" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob0_2_" cx="292" cy="171.5" r="56.5354" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<radialGradient id="blob4_2_" cx="306.5" cy="155" r="14.109" gradientUnits="userSpaceOnUse">
<stop offset="1.020408e-002" style="stop-color:#FF9C12"/>
<stop offset="0.1922" style="stop-color:#FA9712"/>
<stop offset="0.3992" style="stop-color:#ED8A14"/>
<stop offset="0.6186" style="stop-color:#D67316"/>
<stop offset="0.8449" style="stop-color:#B65419"/>
<stop offset="1" style="stop-color:#9C3A1C"/>
</radialGradient>
<linearGradient id="lampTop_2_" gradientUnits="userSpaceOnUse" x1="292" y1="135" x2="292" y2="174">
<stop offset="1.530612e-002" style="stop-color:#000000"/>
<stop offset="0.233" style="stop-color:#050202"/>
<stop offset="0.4808" style="stop-color:#120706"/>
<stop offset="0.7421" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
<linearGradient id="lampBot_2_" gradientUnits="userSpaceOnUse" x1="292.375" y1="439" x2="292.375" y2="379">
<stop offset="5.102041e-003" style="stop-color:#000000"/>
<stop offset="0.2251" style="stop-color:#050202"/>
<stop offset="0.4754" style="stop-color:#120706"/>
<stop offset="0.7394" style="stop-color:#290F0E"/>
<stop offset="1" style="stop-color:#471A19"/>
</linearGradient>
</defs>
<rect fill="url(#bgGrad)" width="600" height="600"/>
<use xlink:href="#glassShape" fill="#EB7619" opacity="0.1"/>
<g class="blobGroup" filter="url(#goo)" clip-path="url(#glassMask)">
<path class="blob0 blob" fill="url(#blob0_2_)" d="M326.2,149.5c-5,19.2-21.4,29.2-37.8,26.6c-16.5-2.9-33.4-12.9-37.1-26.6
c-3.8-13.6,12.5-32.1,37.8-34.9C314.4,111.8,331.3,130.4,326.2,149.5z"/>
<path class="blob1 blob" fill="url(#blob1_2_)" d="M320.5,146.4c-4.4,10.1-16.4,20.2-26.8,25.3c-10.4,5.2-22.4-2.9-26.8-15.2
c-4.4-11.6,7.6-20.4,26.8-25.3C312.9,126.3,324.9,135.6,320.5,146.4z"/>
<path class="blob2 blob" fill="url(#blob2_2_)" d="M278,147.7c2.7-7.1,9.4-15.7,15.4-16.4c5.9-0.4,12.6,8.5,15.4,16.9
c2.7,8.4-4.2,14.9-15.4,14.2C282.2,161.5,275.3,154.8,278,147.7z"/>
<path class="botBlob" fill="url(#botBlob)" d="M354,381.2c6.8,3.4,5.4,7.4-5.6,10.4c-10.7,3.1-31.1,5.1-54.4,8.4
c-23.3,3.3-43.7,0.8-54.4-2.4c-11-3.4-12.4-7.6-5.6-13.8c6.8-7,18.9-14.6,29.6-17.4c11-3.3,20.6-1.8,30.4-1.4
c9.8,0.4,19.4,5.1,30.4,8.3C335.1,376.8,347.2,378.6,354,381.2z"/>
<path class="blob3 blob" fill="url(#blob3Grad)" d="M312.7,147.3c-2.1,16.4-15.3,27.2-23.2,25.3c-8.1-1.8-12.6-13-14.8-24.9
c-1.9-11.8,2.7-22.7,14.8-25.3C301.5,119.6,314.7,130.8,312.7,147.3z" />
<path class="blob4 blob" fill="url(#blob4_2_)" d="M317.8,147.4c-1,8.2-9.8,10.3-13.8,9.3c-4-0.9-6.5-3-7.6-8.9c-1-5.9,2.3-8.5,8.4-9.8
C310.8,136.6,318.8,139.1,317.8,147.4z"/>
</g>
<polygon id="lampTop" fill="url(#lampTop_2_)" points="269,135 262,174 322,174 316,135 "/>
<path id="lampBot" fill="url(#lampBot_2_)" d="M226.8,379.5c2.6,42.8,23.9,54.2,28.3,59.8c3.3,5.4-10,30.8-10,30.8h95.5
c0,0-16.5-25-14.5-30.8s26-15.6,32-60.1C328,379.1,240.3,379.5,226.8,379.5z"/>
<rect y="470" width="600" height="130"/>
</svg>
我自己过了一遍这个教程,然后创建了如下的pen(这是我那个原始版本的微微简略一点的版本,但是它们长得是一模一样的)。
出于让这些pen在这里看起来更好看的目的,我给body
加了一点CSS样式,把滚动条去掉了。
body {
background-color:#000;
overflow: hidden;
}
作为一点点额外的补充,如果你对光斑移动的时间不满意,可以尝试在seek();
一行之后添加一个TimelineMax.timeScale();,如下:
tl.timeScale(12);
这会使得光斑以它们正常速度的12
倍跑起来,颤抖吧骚年!
所以现在你完成这个熔岩灯了——我们已经讲解了相当多的内容了,从AI的提示和小技巧,到SVG滤镜和分组、使用<use>
重用元素,到改变整个GSAP动画的时间。值得欣慰的是代码非常少,因为GSAP真的强大到没朋友。
你可以点击这里下载熔岩灯的AI格式文件。
现在休息一下,然后去准备你的新熔岩灯吧——你可以的!
扩展阅读
本文根据@Chris Gannon的《How To Make An SVG Lava Lamp》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://codepen.io/chrisgannon/post/how-to-make-an-svg-lava-lamp。
如需转载,烦请注明出处:http://www.w3cplus.com/svg/how-to-make-an-svg-lava-lamp.html