几十年来,超级英雄的故事一直吸引着我们--从漫画书中的奇妙世界和人物,到电影中帮助他们获得生命的壮观视觉效果。在本教程中,我们将从中获得灵感,学习如何为网络创建和制作类似超级英雄的插图效果。当然,我们的浏览器中没有好莱坞大制片厂的超级强大的工具,但不用担心,SVG滤镜和遮罩将为我们提供帮助!我们将学习如何重新创建超级英雄的效果。
我们将学习如何重新创造这种很酷的变异效果。如果你不熟悉她的故事,拉文-达科姆,也就是众所周知的魔形女,是《X战警》系列电影中的一个变形者角色。她有一个天然的海军蓝皮肤,可以操纵她的身体,变成她想变成的任何一个人。这当然是一种有用的能力,可用于伪装逃跑,她经常这样做。因此,为了给我们的项目增加一个耐人寻味的背景故事,她被描绘成一张经典风格的通缉海报。
为了准备插图,我们将使用Inkscape 1.1,一个免费的开源矢量绘图编辑器,你可以在这里下载。你可以使用你喜欢的任何其他矢量绘图编辑器。只是要记住,步骤很可能会有所不同。你还需要有至少中级水平的HTML、CSS和JavaScript知识,并熟悉GSAP,我们将使用的动画库。
在我们开始之前,还有一件事
从目前来看,SVG动画过滤器在Chrome中的效果通常比其他浏览器好。请记住,它们也会大大降低页面的速度。SVG过滤器很方便,也很容易使用,但是如果对性能有顾虑的话,可以考虑使用WebGL,因为它是经过GPU优化的。Codrops有很多关于它的资源。
如何为网络准备一个矢量插图
Inkscape是一个强大的矢量图形编辑器,充满了插图和数字艺术的高级功能。另外,它是一个方便的工具,可以用可视化的方式处理SVG,而不是从头开始写所有的代码
。在本教程中,我们不会真正详细介绍Inkscape的插画过程,但你可以从官方文档中了解更多信息。
创建图画
好了,让我们开始吧。按照Inkscape的快速设置指南,它将让你进入一个空的画布界面。前往File > Document Properties ,以便设置页面大小和单位。使用像素而不是毫米或英寸是很重要的,因为在网络上使用像素要容易得多。

Inkscape主屏幕上的文档属性设置为像素单位。
从这里开始,你需要做的就是使用Inkscape的工具创建你的插图,使用形状和曲线绘制一切,或者导入其他图像在屏幕上构图。特别是这幅插图,我在iPad上用Procreate画出线条,然后用File > Import 将它们作为PNG导入Inkscape。然后,我用Path > Trace Bitmap ,从PNG生成高质量的矢量图,并通过手动描摹线条后面的基本形状来着色。最后的结果是由4个不同的部分组成:背景、前景、自然蓝色形态的神秘人和转变为人类形态的神秘人。

最终构图的不同部分。
导出一个优化的SVG
一旦你的插图完成了,就该导出SVG了。构图中的每一个部分都应该放在自己的文件中,因为它们将在页面上组合在一起。
注意。在网络上使用Inkscape或你喜欢的编辑器的原始格式并不是一个好主意。这些格式通常会在输出中添加浏览器无法解释的额外数据,最终只会使文件不必要地变大。
幸运的是,Inkscape有一个超级方便的File > Save as... > Optimized SVG 选项,可以产生一个小得多的SVG。在导出面板上,勾选SVG Output > Enable viewboxing ,以使图像更容易用CSS定位,这一点很重要。其余的默认选项都很好,但我鼓励你也用它们做一些试验。

优化的SVG输出选项。
如果你真的很想优化你的资产,使用SVGO是必须的。在超级整洁的网站SVGOMG上,它可以作为一个命令行工具和网络界面。再次,我建议你启用Prefer viewBox to width/height ,以使定位和尺寸更加灵活。如果你打算手动编辑导出的代码,我也推荐你使用Prettify markup ,它能使输出的代码更易读。
标记和风格
让我们从一个非常简单的HTML5页面结构开始,其中有index.html 、style.css 、index.js 文件和一个images 目录来存储所有导出的SVG。从一个非常简单的HTML5页面开始,我们在头部导入我们的样式表,在底部导入脚本。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mystique</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<svg class="picture" viewBox="0 0 196 296">
<rect id="bg-color" x="0" y="0" width="100%" height="100%"
fill="#4a5eb2"/>
<image id="background" x="0" y="0" width="100%" height="100%"
href="images/background.svg"/>
<image id="transformed" x="0" y="0" width="100%" height="100%"
href="images/transformed.svg"/>
<image id="mystique" x="0" y="0" width="100%" height="100%"
href="images/mystique.svg"/>
<image id="foreground" x="0" y="0" width="100%" height="100%"
href="images/foreground.svg"/>
</svg>
<script src="index.js"></script>
</body>
</html>
在正文中,我们有一个单一的SVG元素,viewBox=“0 0 196 296” 。SVG文件的viewBox参数定义了图片的裁剪区域,前两个数字是左上角的点坐标,最后两个数字分别是宽度和高度。我们必须使用我们在Inkscape中定义的相同尺寸。接下来,我们使用<image> 标签导入图片,每张图片都定位在左上角(x=“0” y=“0”),并填充整个视口(width=“100%” height=“100%”)。在所有的东西后面,我们有一个rect ,上面有我们想要的背景颜色。重要的是要给每个元素一个自己的ID,以便组织。
样式设计很简单,一个带有display: grid的全页面容器帮助我们用place-self: center ,使图片对准中心。为了将所有的东西集中在一起并最终完成构图,我们在背景上添加一个紫色的渐变和一个阴影。
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
body {
display: grid;
background: radial-gradient(at top, #5e4082, #3a124d);
padding: 1rem;
box-sizing: border-box;
}
.picture {
place-self: center;
max-width: 100%;
height: 80vh;
filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.5));
}
结果应该与下图相似。两张图片相互重叠,但这没关系,我们将使用遮罩来创造滑动效果。

这个页面在浏览器中应该是这样的。
设置SVG蒙版
SVG遮罩是一种元素,它根据遮罩内的颜色值信息来定义被遮罩对象的透明度。如果遮罩的一个像素是白色的,那么被遮罩对象的相应像素将是可见的;如果是灰色的,它将是部分透明的;万一是黑色的,它将是完全透明的。遮罩区域外的一切也将是完全透明的。希望下面的图能帮助你更好地理解蒙版的工作原理。

遮罩的工作原理是根据每个像素的颜色值来定义它们的透明度。图片来源。维基共享资源。
为了定义遮罩,我们在SVG的顶部添加一个<defs> 元素,里面有两个<mask> 标签。一个将用于遮蔽mystique(id="mask_mystique" ),另一个将用于她的变换版本(id="mask_transformed" )。每个遮罩只包含一个简单的白色矩形,其大小足以覆盖整个可见区域。然后,我们使用mask="url(#mask_id)" 属性,将遮罩应用于其相应的元素。
<svg class="picture" viewBox="0 0 196 296">
<defs>
<mask id="mask_mystique">
<rect class="mask" x="0" y="-100%" width="100%" height="100%" fill="white"/>
</mask>
<mask id="mask_transformed">
<rect class="mask" x="0" y="0" width="100%" height="100%" fill="white"/>
</mask>
</defs>
<rect id="bg-color" x="0" y="0" width="100%" height="100%" fill="#4a5eb2"/>
<image id="background" x="0" y="0" width="100%" height="100%" href="images/background.svg"/>
<image id="transformed" x="0" y="0" width="100%" height="100%" mask="url(#mask_transformed)" href="images/transformed.svg"/>
<image id="mystique" x="0" y="0" width="100%" height="100%" mask="url(#mask_mystique)" href="images/mystique.svg"/>
<image id="foreground" x="0" y="0" width="100%" height="100%" href="images/foreground.svg"/>
</svg>
Mystique的遮罩被定位在y="-100%" ,这意味着它在视口之外和之上,因此,她将是完全透明的。同时,转变后的Mystique的遮罩以白色覆盖**整个视口,**这意味着她将是完全可见的。如果我们把两个面具都移到底部50%,产生的效果将是两个版本的Mystique都在屏幕上部分显示,就像下面的插图。

Mystique的面具被定位在y="-100%" ,这意味着它在视口之外和之上,因此,她将是完全透明的。同时,转变后的Mystique的遮罩以白色覆盖**整个视口,**这意味着她将完全可见。如果我们把两个面具都移到底部50%,产生的效果将是两个版本的Mystique都在屏幕上部分显示,就像下面的插图。
添加视觉效果
SVG滤镜是一种超级强大的工具,可以为我们无聊的简单SVG增加一些酷感。有很多不同的过滤器选项不在本教程的范围内,但如果你想阅读更多关于它们的内容,Codrops有很多教程详细解释了每一种过滤器。
现在,让我们继续讨论代码。在我们为遮罩创建的同一个<defs> 标签内,我们添加一个<filter id="distort"> 。
<filter id="distort">
<feTurbulence
type="turbulence"
baseFrequency="0.08"
numOctaves="2"
result="turbulence"
/>
<feDisplacementMap
in2="turbulence"
in="SourceGraphic"
scale="50"
/>
</filter>
滤波器是由基元组成的,这些基元也可以堆叠和组合在一起。为了创建 Mystique 的酷炫转换效果,我们要使用feTurbulence 基元,它可以生成一个 Perlin 噪声模式。feTurbulence 的属性type 控制生成的湍流类型,baseFrequency 控制其大小,numOctaves 控制其粗糙度。然后,我们用result="turbulence" 命名输出。
接下来我们要使用feTurbulence 的输出,并将其与SourceGraphic (应用了过滤器的对象的像素)结合成一个feDisplacementMap 基元。这个基元使用in2 的颜色信息对其in 参数的内容进行变形。scale 控制变形的长度。
提示:我强烈建议你玩玩Yoksel的SVG过滤器游戏,如果你想看看这些参数中的每一个是如何影响基元的输出的
。
我们接下来要做的就是把滤波器应用到两个蒙版上。由于遮罩的矩形将被动画化,为了创造流动的变换,我们要将滤波器添加到一个包装组<g> 。否则,滤镜的变形会随着遮罩的静态移动而移动,这样看起来就没有那么酷了
。
如果我们不添加组,动画会是什么样子。
作为本节的总结,下面是最终的SVG应该是什么样子。
<svg class="picture" viewBox="0 0 196 296">
<defs>
<filter id="distort">
<feTurbulence
type="turbulence"
baseFrequency="0.08"
numOctaves="2"
result="turbulence"
/>
<feDisplacementMap
in2="turbulence"
in="SourceGraphic"
scale="50"
/>
</filter>
<mask id="mask_mystique">
<g filter="url(#distort)">
<rect class="mask" x="0" y="-100%" width="100%" height="100%" fill="white"/>
</g>
</mask>
<mask id="mask_transformed">
<g filter="url(#distort)">
<rect class="mask" x="0" y="0" width="100%" height="100%" fill="white"/>
</g>
</mask>
</defs>
<rect id="bg-color" x="0" y="0" width="100%" height="100%" fill="#4a5eb2"/>
<image id="background" x="0" y="0" width="100%" height="100%" href="images/background.svg"/>
<image id="transformed" x="0" y="0" width="100%" height="100%" mask="url(#mask_transformed)" href="images/transformed.svg"/>
<image id="mystique" x="0" y="0" width="100%" height="100%" mask="url(#mask_mystique)" href="images/mystique.svg"/>
<image id="foreground" x="0" y="0" width="100%" height="100%" href="images/foreground.svg"/>
</svg>
用GSAP做动画
GSAP是一个了不起的用于网页动画的JavaScript库。它可以完美地处理从简单到复杂的动画,其精简的API可以顺利地完成工作。我们将在我们的项目中使用它来制作面具矩形的动画。如果你想知道更多关于如何使用GSAP的功能,请查看这里的官方文档。
import gsap from "gsap"
const tl = gsap.timeline({
repeat: -1, // Makes animation repeat infinitely
yoyo: true, // Animation will go back-and-forth like a yoyo
})
tl
.to('.mask', {
translateY: '100%', // Move .mask elements down by 100%
duration: 3,
})
.to('#bg-color', {
attr: {
fill: '#ffd11b' // Change the "fill" attribute of #bg-color
},
duration: 2
}, '<+=1') // Start 1s after the previous animation
看一下代码,首先我们导入GSAP并创建一个来回重复的时间线。接下来,我们通过在Y(垂直)轴上平移遮罩来制作动画,并将#bg-color 元素的颜色改为#ffd11b 黄色。结果应该看起来像介绍中的演示。
超级酷但是,加入一些互动性,使动画跟随鼠标移动呢?鼠标移动事件在网络上是很难处理的,因为它们被频繁触发,迫使浏览器计算动画的次数太多,
。我们可以使用lodash.throttle 来帮助我们确保鼠标移动处理程序不会以太快的速度被触发。如果你对它感到满意,你也可以使用本地的requestAnimationFrame 函数,它非常适合用于节制像这样昂贵的动画。
import gsap from "gsap"
// We'll use throttle to make sure the mousemove event
// doesn't trigger too often
import { throttle } from "lodash"
const tl = gsap.timeline({
paused: true, // Start at a paused state
defaults: {
ease: 'none' // With no easing (linear)
}
})
tl
.to('.mask', {
translateY: 296,
duration: 3,
})
.to('#bg-color', {
attr: {
fill: '#ffd11b'
},
duration: 2
}, '<+=1')
const $picture = document.querySelector('.picture')
// Mouse move handler
function handleMoveEvent(ev) {
// Get the viewport rectangle of the picture
const rect = $picture.getBoundingClientRect();
// Compute the relative mouse position inside the rect
const relPos = (ev.clientY - rect.top) / (rect.bottom - rect.top)
// Use the computed value to control the animation progress
tl.progress(relPos)
}
// Bind the mousemove event, with a throttle to ensure it only
// triggers once at every 60 milliseconds
$picture.addEventListener(
'mousemove', throttle(handleMoveEvent, 60)
)
这应该是这个项目的最终结果,一个完整的、互动的、超酷的SVG超级英雄动画我希望你喜欢它,并且了解了一些关于SVG的超能力
。
The postSuperhero Animation Effect with SVG Filtersappeared first onCodrops.