手把手教你做一个SVG Lava Lamp

编辑推荐: 掘金是一个高质量的技术社区,从 CSS 到 Vue.js,性能优化到开源类库,让你不错过前端开发的每一个技术干货。 点击链接查看最新前端内容,或到各大应用市场搜索「 掘金」下载APP,技术干货尽在掌握中。

运气爆棚的我总是时不时地能创建出大家都喜欢的案例。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遮罩还是有一些不同的)。玻璃的颜色并不要紧,因为我们会在后边的代码中删掉它。后面再详细介绍。

SVG Lava Lamp

现在绘制顶部和底部的部分——注意到在顶部和底部,都有一个非常暗的从橙色到黑色的渐变。这可以创建一个熔岩光溢出的错觉。

SVG Lava Lamp

我们还需要绘制所有的蜡光斑,然后给它们填充一个径向渐变——只需要画四到五个不同尺寸和形状的就ok。使用椭圆工具先画出一个圆,然后应用一个AI通道滤镜(Filter > Warp > Arc Lower),然后做一些弯曲和变形的设置(记得打开预览哟~)。

SVG Lava Lamp

一旦画好了光斑,然后确保较暗的渐变的那部分比较靠近顶部——因为这个灯的光源是在下面的。现在把它们都放置在熔岩灯的顶部周围(如果你见过真正的熔岩灯,就会注意到光斑是在顶部的牙轮里面消失的)。

不要忘了还要画一个更大的更平的光斑放置在底部,这个光斑的顶部只比顶部的碗座高出一点点。虽然这不是一个真正的熔岩灯,但是所有的蜡融化和诗意的漂浮有助于粘稠的效果,所以我们添加SVG模糊颜色矩阵滤镜,结合起来才创建出粘稠的效果。

SVG Lava Lamp

噢我差点忘了!我画了一个桌子(底部的黑色矩形)在那里——否则它看起来就像是漂浮在半空中的。

最后我做了一个带径向渐变的矩形,放置在最底层,作为一个背景阴影。我一开始尝试过在玻璃上应用一个SVG glow滤镜,但是效果非常糟糕,而且从形状上看并没有得到我想要的效果,所以这是一套美观合适的解决方案。

SVG Lava Lamp

现在,如果你碰巧参加了我九月份在英国Brighton的“为什么要有创意的原因”的座谈会,首先感谢你的到来——会议非常好玩!你可能还记得我一直在强调一个非常重要的技巧,在从AI的画板上复制和粘贴你的图形到一个文本编辑器中(或CodePen等等)的时候。我会在这里再次强调,因为这真的非常重要。

一个非常有用的技巧

你可以在AI中把你的SVG保存成.svg格式的文件,但是有一点非常烦人的就是它会输出所有图层,不论它是否可见。它还倾向于生成内联环路,这点我非常不喜欢。

通常我都是挑选好需要的层,然后把它们复制粘贴到我的文本编辑器中。这种方法存在的问题是,当你选择好然后复制粘贴到一个编辑器中时,你粘贴的是一整个SVG的高度和宽度,还是你选中的图层的高度和宽度呢。

当你在AI中选中元素,然后复制粘贴到编辑器中,你粘贴的是一整个SVG的高度和宽度,还是你选中的图层的高度和宽度呢。

也就是说,如果你的玻璃灯图片是在600x600尺寸的画板上,包括顶部和底部的图像,你想要创建一个600x600的SVG,还要让这些元素准确地放置在你希望它出现的位置,你可能会想通过选中这些元素,并将其复制/粘贴到编辑器中就可以得到你想要的结果。但是事实并非如此,因为它并不知道自己粘贴的上下文(画板);所以它选择的是对应图层的高度和宽度,并将其作为结果SVG的高度和宽度。

SVG Lava Lamp

注意变换面板——它显示了你选中图层的宽度是131.304px,高度是304px。当你将其复制粘贴到一个HTML页面中时,它的SVG如下:

SVG Lava Lamp

(我刚刚意识到我没有画好——底座顶部的线竟然没有对齐!!!)

高亮显示SVG的宽度(131.3)和高度(304)——生成的SVG和选中图层是相同的尺寸,也就是说你失去了600x600的画板,它们现在并没有按照我们希望的放置在中心的位置。

在AI中画一个和你的画板一样尺寸的矩形,然后在将画板上的内容复制到编辑器时,和其它的元素一起选中它。

这个简单的解决方案(我知道能够写成一个教程的东西从来都不是简单的,但是在这种特定情况下,它真的很简单!)就是在AI中绘制一个矩形,和你的画板一样的尺寸,然后每次复制内容到编辑器时一起选中它。从现在起,我把它当做一个“上下文”图层。你可以在后面从SVG代码中丢弃这个上下文图层,但是在复制/粘贴的过程中这真的是必不可少的,这样生成的SVG才可以保持600x600的画板尺寸(因为上下文图层和画板是一样的大小)。对吧?

所以现在是...

SVG Lava Lamp

...然后在HTML中生成...

SVG Lava Lamp

现在看起来好像好点了。

所以,现在你需要添加蜡光斑,你可以把它们全部选中,然后添加上下文图层(保持按住shift键然后选中它)——这样它们才可以保留在正确的位置。

我习惯使用Sublime Text作为“中间人”来整理我的SVG,然后挑选我需要的部分。这不是绝对必要的,但是我喜欢Sublime的“查找/替换/正则表达式”功能,所以用来帮我执行清理任务是非常合适的。你可以很方便地把它们都粘贴到CodePen的HTML面板中。

有关图层的一个简短的说明——我给所有图层都命名了,即使我不打算给所有图层都添加动画。图层名在SVG中会变成它们自身的id(尽管有AI自己加上的恼人的数字和下划线╭(╯^╰)╮)。给图层命名使得它们之后放到在页面中更容易被识别。

SVG Lava Lamp

正如我上面提到的,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>实例中添加这个样式。如果我们保留了初始glassShapefill属性,我们就不能在后面的<use>实例中重写这个属性了。

现在你的预览面板中的玻璃和背景应该显示如下:

SVG Lava Lamp

还醒着吗朋友?对的,有人开了扇窗。

接下来我们把桌子摆上,还有熔岩灯的底部和顶部。选中它们,记得包括上下文图层,然后把它们复制到你的文本编辑器中。

<!-- 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>

再次,我们把lampToplampBottableTop里的_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>

现在复制lampToplampBottableTop,然后把它们粘贴到玻璃图形的<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>

你的预览面板展示的内容应该是长这样的:

SVG Lava Lamp

终于论到光斑了!

回到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预览面板应该如下所示——如果它正常的话:

SVG Lava Lamp

给光斑分组、添加遮罩

还记得我们把glassShape放到clipPath中了吗?好了我们现在要使用它来裁剪所有的光斑,这样它们看起来就是在熔岩灯内的,但是首先我们需要把所有的光斑放到一组。这样我们就可以一次性地裁剪整个分组了。

所以,在codepen中,找到idblob0的路径,在它上面添加一个<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预览面板加上裁剪的光斑之后,现在应该是长这样的:

SVG Lava Lamp

为了创建粘稠效果的滤镜,需要添加一段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设置面板如下所示:

SVG Lava Lamp

最后的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路径的初始XY位置的方式。就GSAP而言,当你让一条路径从它的初始位置移动(即从AI中复制过来,粘贴的位置),它将会默认XY的位置为(0,0),不论它是处在SVG画布的哪个位置。所以尽管光斑看起来是,X差不多为250Y差不多为120,它们都会被认为是在(0,0)的位置。这也就是说每个光斑都会相对它的初始粘贴位置向下移260px

GSAP默认路径的XY的位置为(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

彦子

在校学生,本科计算机专业。逗比一枚,热爱前端热爱生活,喜欢CSS喜欢JavaScript喜欢SVG,爱玩PS玩AI玩啊逗比的软件。努力向上,厚积薄发。

如需转载,烦请注明出处:http://www.w3cplus.com/svg/how-to-make-an-svg-lava-lamp.html

返回顶部