欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

如何使用CSS制作节日SVG图标动画

程序员文章站 2024-01-18 19:19:52
...

正是这个季节,因此在本教程中,我将逐步创建一些CSS动画,以假日为主题的SVG图标。 Iconmelon上有一些很棒的图标,该网站上有许多免费的矢量图标集,可让您尽其所能 我使用的图标来自设计师Sam Jones 因此,为自己准备一杯蛋酒,将笔记本电脑拉到yule日志上,让我们开始吧!

SVG和网络

如果您对在网络上使用SVG感兴趣,则图标是一个不错的起点。 SVG灵活,独立于分辨率且重量轻,因此图标自然适合于矢量格式。 另外,就像HTML一样,SVG可以轻松地用CSS样式化,其中包括CSS3动画。 在图标中添加一些与动画的交互性,可以为用户创造愉悦的体验,还可以添加有关图标代表的内容。

有关SVG和Web的介绍,请查看SVG文件:从Illustrator到Web

注意:在撰写本文时,以下演示使用了尖端技术,在某些浏览器(例如Internet Explorer)中,尚不支持这些技术。 如果您按照本教程进行操作,则最好使用Chrome或Safari。 使用适当的属性前缀完全可以实现Mozilla支持。 您当然可以期望将来对这些技术的支持会有所改善。

另外:在本文中,为了简洁和易读,我从一些CSS属性中省略了一些必要的浏览器前缀。 如果您想轻松编写无前缀CSS,请查看Lea Verou的无前缀库。 您也可以尝试在Codepen上创建演示,可以轻松配置为使用prefixfree。


准备要编辑的SVG代码

SVG的最大问题之一就是代码难以处理。 乍一看,由我选择的矢量图形编辑器Illustrator导出的SVG代码非常不可读。 在这方面, Inkscape实际上在导出SVG方面做得更好,但是我发现简化和格式化代码可以大大简化代码的阅读和使用。

这是我将演示的第一个动画示例的SVG代码,一个闪烁的圣诞灯。

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
<path id="outline" d="M38.178,12.142H25.822v10.723c-1.605,2.67-2.461,6.529-2.461,11.406c0,9.473,4.748,17.587,8.637,17.587
 s8.641-8.114,8.641-17.587c0-4.881-0.854-8.744-2.461-11.412V12.142z"/>
<rect id="basefill" x="29.822" y="16.142" fill="#4D4B4C" width="4.355" height="4.273"/>
<path id="lightfill" fill="#FFFFFF" d="M31.998,47.768c-1.402-0.959-4.637-6.229-4.637-13.497c0-5.775,1.271-8.566,2.207-9.855
 h4.857c0.945,1.293,2.213,4.08,2.213,9.855C36.639,41.542,33.402,46.809,31.998,47.768z"/>
</svg>

此代码是从我的矢量编辑工具Adobe Illustrator导出的。 乍看之下几乎是不可读的。 这是简化的相同标记:

<svg class="svg-light" 
	viewBox="0 0 64 64" 
	xmlns="http://www.w3.org/2000/svg"
	>

	<path class="outline"
		d="M38.178,12.142H25.823v10.723c-1.606,2.67-2.461,6.529-2.461,11.406c0,9.473,4.748,17.587,8.636,17.587c3.889,0,8.641-8.114,8.641-17.587c0-4.881-0.854-8.744-2.461-11.412V12.142z"
		/>

	<rect class="base"
		x="29.822"
		y="16.142"
		width="4.355"
		height="4.273"
	 	/>

	<path class="bulb"
		d="M31.998,47.768c-1.402-0.959-4.637-6.229-4.637-13.497c0-5.775,1.272-8.566,2.207-9.856h4.858c0.945,1.293,2.213,4.081,2.213,9.856C36.639,41.542,33.402,46.809,31.998,47.768"
	 	/>
</svg>

我通过删除程序默认输出的许多额外标记,大大简化了该xml。 我的基本SVG元素包含以下内容:

  • 一类: svg-light 我已经使用svg-前缀轻松定位特定SVG中的元素。
  • viewbox属性。 viewbox属性的值定义文档的长宽比,并等于Illustrator中画板的大小。
  • xmnls属性。 此属性定义SVGXML名称空间,并帮助某些用户代理理解标记。

于定义了组成图像形状嵌套在SVG内部的元件,如pathscirclesrects ,我已经内嵌其开口标签施加类。 元素的所有内联属性,例如其坐标,都已换行。 另外,我在SVG基本标签下缩进了所有内部元素。

所有这些工作是有原因的。 首先,它使代码更易于阅读。 第二,在我选择的代码编辑器Sublime Text 3中,我可以轻松折叠单个SVG元素或整个SVG,而类名仍有助于保留有关这些元素是什么的上下文。


圣诞灯饰

好吧,让我们进入节日气氛,为闪烁的圣诞灯设置动画! 这是我们将要实现的目标:

CodePen查看 Noah Blon@noahblon )的笔

我想要做的是为我在SVG中提供一类bulb的path元素制作动画。

<path class="bulb"
	d="M31.998,47.768c-1.402-0.959-4.637-6.229-4.637-13.497c0-5.775,1.272-8.566,2.207-9.856h4.858c0.945,1.293,2.213,4.081,2.213,9.856C36.639,41.542,33.402,46.809,31.998,47.768"
	/>

使用CSS,我将给灯泡填充颜色并定义其动画属性。

.svg-light .bulb {
    fill: hsl(204, 70%, 23%);
    animation-name: glow-blue;
    animation-duration: 1s;
    animation-iteration-count: infinite;
    animation-timing-function: ease-in-out;
    animation-direction: alternate;
}

fill属性允许我们设置SVG元素的颜色。 如果可能的话,我喜欢使用HSL(色相,饱和度,亮度)定义颜色值,因为使用起来非常直观。 在这里,我选择了蓝色(色调204),并将亮度值保持在23%的低水平,这意味着我们将获得深蓝色。

我将灯泡设置为通过称为glow-blue的关键帧动画进行动画处理。 动画的持续时间为1秒。 动画无限迭代,这意味着它将永远运行。 动画的定时在关键帧的开始和结束处得到缓解,从而在动画的开始和结束点处创建了更加平滑的过渡。 最后,将动画设置为交替,这意味着它将从头到尾来回移动并再次来回移动。

提示:您可能知道CSS动画规则有一种简化的语法,但是我通常更喜欢将规则拆分开,以便在链接多个动画时更易于理解,修改和共享。

现在,我将定义glow-blue关键帧动画:

@keyframes glow-blue {
    0% { fill: hsl(204, 80%, 23%); }
    100% { fill: hsl(204, 80%, 63%); }
}

在这里,我设置了要应用此动画的元素的开始和结束填充颜色。 唯一改变的值是颜色的亮度(hsl中的“ l”位),这意味着灯光将从同一色调的较暗版本变亮。 这就是HSL提供的直观语法。

因为我已经定义了动画无限交替,所以灯光会从黑暗变为灯光,并且永不停止。 因此,它似乎会闪烁。

动画多个灯光

好,现在让我们引导内部的Clark W. Griswold并为整个圣诞灯设置动画。 这就是我要创建的:

请参阅CodePen上的Noah Blon@noahblon )的Pen 540257e4a8b727e435c8e4033602ebb0

我创建了五种不同颜色的灯。 每盏灯都以20%的宽度包裹在div中。 这些div然后向左浮动,使它们彼此内联。 由于我尚未将SVG设置为设置的高度或宽度并保留了viewbox属性,因此SVG可以适应其父级的大小而不会丢失其长宽比或质量。 只是SVG的巨大优势之一。

<svg class="svg-light svg-light--red">

对于每个SVG,我都使用颜色后缀(例如svg-light--red)扩展了基本svg-light类。 这是我用来为许多灯光设置动画的规则的摘录:

.svg-light .bulb {
	animation-duration: 1s;
	animation-iteration-count: infinite;
	animation-timing-function: ease-in-out;
	animation-direction: alternate;
}

.svg-light--red .bulb {
	fill: hsl(6, 63%, 16%);
	animation-name: glow-red;
	animation-delay: .5s;
	animation-duration: 1.25s;
}

@keyframes glow-red {
	0% { fill: hsl(6, 63%, 16%); }
	100% { fill: hsl(6, 63%, 56%); }
}

基本的动画属性仍将应用于svg-light的基类,以便可以在所有灯光之间共享它们。 对于每种颜色变化,我创建了一个不同的关键帧动画,例如, glow-redglow-blue并为其赋予了不同的动画延迟和持续时间。 这样,指示灯将以适当的颜色闪烁,并且所有指示灯不会同时闪烁。


红鼻子驯鹿鲁道夫

我将使用与上述相同的概念来制作最著名的驯鹿鲁道夫的动画。 这是最终结果:

见笔SVG鲁道夫动画图标使用CSS诺亚伦( @noahblon )上CodePen

首先,我将为他发光的红鼻子设置动画:

.svg-rudolph .nose {
    animation-name: glow;
    animation-duration: 6s;
    animation-iteration-count: infinite;
    animation-timing-function: ease-in-out;
    animation-direction: alternate;
}

@keyframes glow {
    0% { fill: hsl(6, 93%, 16%); }
    50% { fill: hsl(6, 93%, 56%); }
    100% { fill: hsl(6, 93%, 56%); }
}

这看起来很像我们的圣诞灯。 在关键帧动画中,我将动画设置为50%,然后设置为100%。 由于动画持续时间为六秒,这意味着在三秒钟内,鼻子将变为浅红色,并在动画结束前再保持该颜色三秒钟。 另外,由于我将动画设置为替代,所以现在它将从头到尾运行。 因此,鼻子将在另外三秒内保持全红状态,最后在最后三秒内变黑。 了解关键帧百分比和动画定义(例如持续时间)之间的相互作用是创建有效CSS动画的关键。

我还对Rudy鼻子上的亮点应用了过渡:

.svg-rudolph .nose-highlight {
    fill-opacity: 0;
    animation-name: highlight-fade;
    animation-duration: 6s;
    animation-iteration-count: infinite;
    animation-timing-function: ease-in-out;
    animation-direction: alternate;
}

@keyframes highlight-fade {
    0% { fill-opacity: 0; }
    25% { fill-opacity: 0; }
    100% { fill-opacity: 1; }
}

在这里,我为另一个SVG属性设置了动画,即fill-opacity 此属性的取值介于0到1之间; 0为完全透明,1为完全不透明。 最后,我将让Rudy眨眨眼,使他的生活更加生动:

.svg-rudolph .eye {
    animation-name: blink;
    animation-duration: 8s;
    animation-iteration-count: infinite;
    transform-origin: 50%;
}

@keyframes blink {
    0% { transform: scaleX(1) scaleY(1); }
    1% { transform: scaleX(1.3) scaleY(0.1); }
    2% { transform: scaleX(1) scaleY(1); }
    60% { transform: scaleX(1) scaleY(1); }
    61% { transform: scaleX(1.3) scaleY(0.1);}
    62% { transform: scaleX(1) scaleY(1); }
    100% { transform: scaleX(1) scaleY(1); }
}

我已经创建了一个名为blink的动画。 该动画运行八秒钟,永不停止。 这次我不改变动画,而是动画将运行到最后,然后从头开始。

在关键帧中,通过操纵X和Y轴上的眼睛比例来创建闪烁的动画。 例如,在1%的标记处,眼睛在X轴上的大小缩放为1.3倍,在Y轴上的大小缩放为正常大小的0.1倍。 换句话说,它们变宽了一些,变短了一些。 在动画持续时间的百分之一之后,眼睛的大小恢复正常。 因此,规模变化发生得非常快。 8秒/ 100 = 8分之一秒。

使用transform为SVG元素设置动画的关键组成部分是设置元素transform-origin 在大多数情况下,为了在SVG中正确应用变换,我们必须将变换坐标的原点定义为元素的中心。 与HTML元素不同,默认情况下,SVG元素的变换原点是其左上角,即(0,0)坐标。 通过将transform-origin设置为(50%,50%),变换的X和Y轴的原点将位于元素的中心,然后可以正确应用变换。

注意: Firefox在转换原点时遇到问题。 不幸的是,将转换原点设置为50%实际上会重置元素的X / Y坐标。 一种解决方法是将元素转换回其原始位置。


丁东高中

对于此演示,我将为这样的铃声制作动画:

请参阅CodePen上的Noah Blon@noahblon )的Pen 63cdc3e8e785028deb35132d889b6090

让我们看一下SVG标记的摘录:

<svg class="svg-bell" viewBox="0 0 88 72" xmlns="http://www.w3.org/2000/svg">
		<g class="group-striker">
			<circle class="outline"
				cx="43.998" 
				cy="54.571" 
				r="7.99"
				/>
			<circle class="fill"
				cx="43.998" 
				cy="54.567" 
				r="3.99"
				/>
		</g>
		<g class="group-bell">
			<path class="outline"
				d="M71.5,38.184h-3.291l-6.213-21.879c-1.367-4.816-5.951-8.693-10.904-9.514C50.91,3.02,47.812,0,43.996,0c-3.812,0-6.91,3.018-7.092,6.787c-4.957,0.822-9.539,4.697-10.908,9.514l-6.211,21.883h-3.289l-4.498,15.85h19.251H36h15.994h3.963h20.041L71.5,38.184z M40.975,6.611C41.229,5.143,42.455,4,43.996,4c1.543,0,2.77,1.143,3.025,2.615L40.975,6.611z"
				/>
			<path class="fill"
				d="M29.844,17.395c1.045-3.678,5.156-6.783,8.975-6.783l10.355,0.004c3.82,0,7.93,3.105,8.975,6.783l5.902,20.785H23.943L29.844,17.395z"
				/>
			<polygon class="fill"
				points="19.52,42.184 68.477,42.184 70.705,50.033 17.291,50.033"
				/>
		</g>
	</svg>

我已经包装好钟形轮廓并填充了<g> (或组)标签。 此标记对于组织元素非常有用,类似于您可以使用<div>包装多个HTML元素的方式。 可以将动画应用于组。 因为在这种情况下,我希望钟形的填充和轮廓都旋转,所以我可以只旋转组而不是分别旋转每个元素。

.svg-bell .group-bell {
    animation-name: bell-ring;
    animation-duration: 3s;
    animation-iteration-count: infinite;
    animation-timing-function: ease-in-out;
    animation-delay: -1.5s;
    animation-direction: alternate;
    transform-origin: 50%;
}

@keyframes bell-ring {
    0% { transform: rotate(27deg); }
    100% { transform: rotate(-27deg); }
}

到目前为止,这个CSS应该已经很熟悉了,但是有一些新的事情正在发生。 首先,在关键帧动画中,钟形被转换了,但是我不是在转换比例,而是在转换元素的旋转值。 此动画使铃铛在27到-27度之间摆动。

我做的另一件事是对animation-delay使用负值。 负值会使动画开始该时间段进入动画。 在这种情况下,动画将开始在动画中播放1.5秒,而不是在1.5秒的延迟后开始播放动画。 这样,铃铛将从动画开始1.5秒的空档位置开始,而不是动画开始0秒的空转位置开始。

.svg-bell .striker {
    animation-name: striker-move;
    animation-duration: 3s;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
    animation-delay: 1.5s;
    animation-direction: alternate;
    transform-origin: 50%;
}

@keyframes striker-move {
    0% { transform: translateX(3px); }
    100% { transform: translateX(-3px); }
}

我对包含铃铛前锋元素的组应用了类似的动画。 但是,这次,我是沿X轴平移或移动元素,而不是旋转它们,因此撞针将左右摆动。


让它下雪吧!

对于此动画,我将为落在雪球内部的雪设置动画。

请参阅CodePen上的Noah Blon@noahblon )的Pen 2addb5f98c757d61cec87bdcacb5870d

我创建了一堆用于表示雪的圆形元素,并将这些元素放在雪球的周围,并将它们包裹在<g>标记中。

由于我已将剪切路径应用于包含雪的组,因此在雪球之外看不到雪。 剪切路径是可以应用于SVG元素的形状,可以遮盖其中的其他形状。 在我们的地球仪示例中,我创建了一个圆形的剪切路径,它覆盖了地球的内部。

<defs>
	<clipPath id="globeClipPath">
  		<circle cx="32" cy="31" r="26.825"/>
	</clipPath>
</defs>

<clipPath>标签是我们的masking元素,要实现它,我们必须给它一个ID。

我已经将剪切路径包装在defs标签中。 SVG允许我们创建以后可以重用的元素,例如剪切路径,过滤器或可以冲压出的形状。 最佳实践是将定义(例如剪切路径)包装在defs标签中,以便可以更轻松地读取SVG。

要应用剪切路径,我们在SVG元素的内联剪切路径属性中引用其url(在本例中为ID,其前面带有哈希符号):

<g class="group-snow" clip-path="url(#globeClipPath)">
    <circle class="snow" 
        cx="49.498" 
        cy="8.482" 
        r="2.5"
        />
    <circle class="snow" 
        cx="35.748" 
        y="2.783" 
        r="2.5"
        />
    <circle class="snow" 
        cx="21.001" 
        cy="4.728" 
        r="2.5"
        />
    <circle class="snow" 
        cx="28.25" 
        cy="2.783" 
        r="2.5"
        />
    <circle class="snow" 
        cx="42.997" 
        cy="4.728" 
        r="2.5"
        />
    <circle class="snow" 
        cx="14.502" 
        cy="8.482" 
        r="2.5"
        />
    <circle class="snow" 
        cx="9.194" 
        cy="13.793" 
        r="2.5"
        />
    <circle class="snow" 
        cx="54.806" 
        cy="13.793" 
        r="2.5"
        />
</g>

现在仅在该圆形剪切路径内部可见雪。

使用与我之前介绍的技术相同的方法对雪进行动画处理; 沿Y轴平移,并且随着动画结束,填充不透明度接近零。

.svg-snowglobe .snow { 
	animation-name: snowfall;
	animation-duration: 10s;
	animation-iteration-count: infinite;
	animation-timing-function: ease-in;
}

.svg-snowglobe .snow:nth-child(1) { animation-delay: 2s; }
.svg-snowglobe .snow:nth-child(2) { animation-delay: 4s; }
.svg-snowglobe .snow:nth-child(3) { animation-delay: 6s; }
.svg-snowglobe .snow:nth-child(4) { animation-delay: 8s; }
.svg-snowglobe .snow:nth-child(5) { animation-delay: 10s; }
.svg-snowglobe .snow:nth-child(6) { animation-delay: 12s; }
.svg-snowglobe .snow:nth-child(7) { animation-delay: 14s; }
.svg-snowglobe .snow:nth-child(8) { animation-delay: 16s; }
.svg-snowglobe .snow:nth-child(9) { animation-delay: 18s; }
.svg-snowglobe .snow:nth-child(10) { animation-delay: 20s; }

是的,CSS3选择器可用于SVG元素! 在这里,我给每个降雪元素指定了不同的延迟,因此它们不会一次全部掉落。


季节的问候

最后,我将为基于SVG的文本设置动画,以实现如下结果:

CodePen查看 Noah Blon@noahblon )的笔消息

SVG使我们能够使用CSS将笔画应用于SVG元素。 在上一个动画中,我将向您展示如何逐步绘制元素的笔触。

为了实现此动画,我使用了以下笔触属性:

  • stroke-width :笔划的宽度。 这是相对于SVG的大小,因此是响应性的。
  • stroke :笔触的颜色。
  • stroke-dasharray :定义虚线描边。 交替值数组定义虚线绘制部分的长度以及虚线之间的空白区域。
  • stroke-dashoffset :定义相对于路径长度的笔画起始位置。

设置描边文本需要在图形编辑器中进行一些工作。 我的工作流程如下:

  1. 创建一个文本元素。
  2. 将该文本转换为矢量路径。
  3. 将这些路径合并为复合路径。

这是我设置动画CSS:

.svg-message .text {
    stroke-width: 1px;
    stroke: hsl(6, 63%, 36%);
    stroke-dasharray: 1865.753px 1865.753px;
    stroke-dashoffset:  1865.753px ;
    fill-opacity: 0;
    fill: hsl(6, 63%, 36%);
    animation-name: stroke, fill;
    animation-duration: 1s;
    animation-delay: 0, 1s;
    animation-iteration-count: 1;
    animation-timing-function: ease-in-out;
    animation-fill-mode: forwards;
}

@keyframes fadeIn {
    0% { fill-opacity: 0; }
    100% { fill-opacity: 1; }
}

@keyframes drawStroke {
    100% { stroke-dashoffset: 0 }
}

我已将stroke-dasharray属性定义为总路径的长度(您可以使用Object选项在Illustrator中的Document Info Palette下找到此值)。 然后,我给stroke-dashoffset设置了路径总长度的值,这使整个笔划都无法显示。 然后,通过关键帧为stroke-dashoffset属性设置动画,笔画将逐渐在屏幕上绘制。

如果您想了解更多有关此技术的信息,请查看Jake Archibald的SVG中的Animated线描

我还设置了线条绘制完成后使用淡入淡出的属性来填充文本,该属性类似于我之前对snowglobe动画所做的操作。


借助SVG和CSS进一步发展

在本教程中,我已经演示了使用CSS和SVG可以创建一些非常有效的动画。 如果您想使用所有代码以及一些其他动画,可以从Github下载示例,在Codepen上查看我的收藏集

如果您想变得更高级,可以探索使用JavaScript控制CSS动画,或者用更复杂JavaScript动画来补充CSS动画,例如令人惊叹的SVG JS库Snap SVG支持的动画。

感谢您跟随本教程的学习,我迫不及待想看到您提出的创意!

翻译自: https://webdesign.tutsplus.com/tutorials/how-to-animate-festive-svg-icons-with-css--webdesign-17658