使用SVG完成悬浮时形状样式变化的效果
本文由韩聪根据MARY LOU的《SHAPE HOVER EFFECT WITH SVG》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://tympanus.net/codrops/2014/01/07/shape-hover-effect-with-svg,以及作者相关信息
——作者:MARY LOU
——译者:韩聪
在这篇教程里,我们将重新创建一个类似The Christmas Experiments网站中看到的hover样式。我们将通过SVG制作出形状,然后使用Snap.svg做出hover时的动画效果。
如果你已经访问过The Christmas Experiments最新版本的网站,你可能会注意到其中Christmas calendar很酷的三角状的hover效果。那个形状其实是一个带边框的三角形。今天我会向您展示,如何使用SVG和Snap.svg做出同样的效果。我们的想法是,使用一条路径创建一个SVG,用它来表示caption的形状背景,然后在hover时改变这个路径。完成这一任务有很多种创作的可能性,今天我们将做出三个不同的示例。使用SVG的好处是,我们可以根据父容器的大小调整形状的大小,使一切都成为流动的。
demo里使用的插画由Isaac Montemayor创作。可以在他的website或Dribbble中查看原始作品。
那么,现在开始吧!
标记
首先我们要做的,是在类似Adobe Illustrator 或 Inkscape的矢量图编辑器中绘制两个形状。每个形状将包括一条路径,完成之后,复制路径的各个点,这些点将在标记中使用。注意我们已经将一个多边形装换成了一条路径。如果你使用的是Inkscape,你可以通过这样的步骤实现:选择对象,Path>Object to Path
。路径的点可以通过Edit>XML Editor…
获取到。这将会打开如下面截图中看到的视图:
“d”(路径数据)值就是你需要的。
对于这个标记,我们将有一个class为“grid
”的区域,其中包括被包在锚点中的figure
。你也可以在这儿使用一个列表,这样将会需要一些额外的标记。
这个figure
将包含图象、最初可见的形状和一个figcaption
:
<section id="grid" class="grid clearfix">
<a href="#" data-path-hover="m 180,34.57627 -180,0 L 0,0 180,0 z">
<figure>
<img src="img/1.png" />
<svg viewBox="0 0 180 320" preserveAspectRatio="none"><path d="M 180,160 0,218 0,0 180,0 z"/></svg>
<figcaption>
<h2>Crystalline</h2>
<p>Soko radicchio bunya nuts gram dulse.</p>
<button>View</button>
</figcaption>
</figure>
</a>
<!-- ... -->
</section>
对于每个图象,SVG都会有其相应的viewBox值,并且设置属性preserveAspectRatio的值为“none”。这将允许我们缩放和伸展形状到我们想要的尺寸,即100%。我们将在样式表中定义宽度和高度。hover路径的信息将会存储在锚点的数据属性data-path-hover
中。
CSS
注意CSS将不会包括任何vendor prefixes(-webkit、-moz等),但你可以在文件中找到它们。
我们将看到的样式是为全部三个示例而写的。首先,我们将查看公共样式,然后为不同demo分别设置样式。
让我们从grid
开始吧。我们需要使它居中,然后设置一个max-width
和一个百分比表示的width
,让其成为流体的:
.grid {
margin: 40px auto 120px;
max-width: 1000px;
width: 90%;
}
锚点应该向左浮动,由于我们想让它们成为流式的,并且一行显示4个项,我们需要为它们设置一个250px的max-width,并且有一个值为25%的width。稍后我们将会为更小尺寸的屏幕定义样式:
.grid a {
float: left;
max-width: 250px;
width: 25%;
color: #333;
}
要为奇数项创建一些偏移,我们需要设置margin-top为30px,margin-bottom为-30px。这将使grid看起来更加漂亮,如The Christmas Experiments网站中显示的那样:
.grid a:nth-child(odd) {
margin: 30px 0 -30px 0;
}
因为我们需要一些绝对定位的子元素,figure应该使用相对定位。由于hover效果可能引起一些溢出,而我们不想这些溢出被看到,因此设置overflow为“hidden”:
.grid figure {
position: relative;
overflow: hidden;
margin: 5px;
background: #333;
}
图象将占据其父元素的全部宽度,并且其opacity为0.7。hover时,我们要使opacity动态变化,因此增加了一个transition:
.grid figure img {
position: relative;
display: block;
width: 100%;
opacity: 0.7;
transition: opacity 0.3s;
}
figcaption
需要被绝对定位,我们将拉伸它直到覆盖整个项:
.grid figcaption {
position: absolute;
top: 0;
z-index: 11;
padding: 10px;
width: 100%;
height: 100%;
text-align: center;
}
标题和段落在hover时都将会动态变化,因此我们给它们添加上相应的transition,然后稍微移动它们:
.grid figcaption h2 {
margin: 0 0 20px 0;
color: #3498db;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 300;
font-size: 130%;
transition: transform 0.3s;
}
.grid figcaption p {
padding: 0 20px;
color: #aaa;
font-weight: 300;
transition: opacity 0.3s, transform 0.3s;
}
.grid figcaption h2,
.grid figcaption p {
transform: translateY(50px);
}
下面是三个示例中button的公共样式。button也是动态变化的,因此我们将为其opacity和transform添加一个transition:
.grid figure button {
position: absolute;
padding: 4px 20px;
border: none;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: bold;
transition: opacity 0.3s, transform 0.3s;
}
为了避免一些闪烁和毛刺,我们需要给动画元素及其父元素的backface-visibility设为hidden:
.grid figcaption,
.grid figcaption h2,
.grid figcaption p,
.grid figure button {
backface-visibility: hidden;
}
SVG也将是绝对定位的,并且我们会通过把width和height都设置为100%来拉伸它,直到覆盖整个项。top值为-1px而不是0确保了它在Firefox (26.0 / Mac)中不会出现奇怪的行。
.grid svg {
position: absolute;
top: -1px; /* fixes rendering issue in FF */
z-index: 10;
width: 100%;
height: 100%;
}
路径的颜色将被填充为白色:
.grid svg path {
fill: #fff;
}
在这里你也可以为路径填加一些过渡效果,如hover时改变上面的填充颜色。
通常的锚点hover效果如下所示:
.grid a:hover figure img {
opacity: 1;
}
.grid a:hover figcaption h2,
.grid a:hover figcaption p {
transform: translateY(0);
}
.grid a:hover figcaption p {
opacity: 0;
}
当段落标题滑上去并隐藏之后,图像的透明度将被设置成1,并且,标题行也会上移。
在第一个和第三个示例中,我们想为按钮设置一个白色的边框,并将按钮置于父容器的中间。它最初是隐藏并缩小的。其它的transform则用于将按钮拉至目标位置然后居中。hover时,button会放大、渐渐显示出来。
.demo-1 body {
background: #3498db;
}
.demo-1 .grid figure button,
.demo-3 .grid figure button {
top: 50%;
left: 50%;
border: 3px solid #fff;
background: transparent;
color: #fff;
opacity: 0;
transform: translateY(-50%) translateX(-50%) scale(0.25);
}
.demo-1 .grid a:hover figure button,
.demo-3 .grid a:hover figure button {
opacity: 1;
transform: translateY(-50%) translateX(-50%) scale(1);
}
在第二个demo中,我们将重定义一些颜色,并将button隐藏在figure的底部。为此我们设置bottom为0,并且定义其高度为100%。hover时,它会通过“ease-out”这个函数实现上滑效果。
.demo-2 body {
background: #e74c3c;
}
.demo-2 .grid figcaption h2 {
color: #e74c3c;
}
.demo-2 .grid figcaption p {
transition-delay: 0.05s;
}
.demo-2 .grid figure button {
bottom: 0;
left: 0;
padding: 15px;
width: 100%;
background: #fff;
color: #333;
font-weight: 300;
transform: translateY(100%);
}
.demo-2 .grid a:hover figure button {
transition-timing-function: ease-out;
transform: translateY(0);
}
第二个和第三个示例中的标题行与段落将使用cubic-bezier 函数模拟弹性过渡效果。段落的hover效果中也将设置另一个无延迟的时间。这将确保SVG形状到达顶部之前段落快速消失。
.demo-2 .grid figcaption h2,
.demo-2 .grid figcaption p,
.demo-3 .grid figcaption h2,
.demo-3 .grid figcaption p {
timing-function: cubic-bezier(0.250, 0.250, 0.115, 1.445);
}
.demo-2 .grid a:hover figcaption p,
.demo-3 .grid a:hover figcaption p {
transition-delay: 0s;
transition-duration: 0.1s;
}
对于第三个demo,我们将改变一些颜色,使标题行hover时平移一点儿而不是设置为0.
.demo-3 body {
background: #52be7f;
}
.demo-3 .grid figcaption h2 {
color: #52be7f;
}
.demo-3 .grid a:hover figcaption h2 {
transform: translateY(5px);
}
对于更小的屏幕,我们想改变每一行显示的项目数量,因此我们将重置其width和偶数子元素的margin。第2、5、8、11(3n-1序列)等等这些个锚点应该有一个margin。Tips:如果你想快速寻找一行数字的序列,你可以去WolframAlpha这样的网站,然后键入你的数字,你会在“Possible sequence identification”对应的位置找到序列定义。
对于再小一些的屏幕,我们将调整grid的max-width,重定义标题元素的一些margin:
@media screen and (max-width: 58em) {
.grid a {
width: 33.333%;
}
.grid a:nth-child(odd) {
margin: 0;
}
.grid a:nth-child(3n-1) {
margin: 30px 0 -30px 0;
}
}
@media screen and (max-width: 45em) {
.grid {
max-width: 500px;
}
.grid a {
width: 50%;
}
.grid a:nth-child(3n-1) {
margin: 0;
}
.grid a:nth-child(even) {
margin: 30px 0 -30px 0;
}
.grid figcaption h2 {
margin-bottom: 0px;
transform: translateY(30px);
}
.grid figcaption p {
margin: 0;
padding: 0 10px;
}
}
@media screen and (max-width: 27em) {
.grid {
max-width: 250px;
}
.grid a {
width: 100%;
}
.grid a:nth-child(even) {
margin: 0;
}
}
这就是所有的style啦!让我们来看看JavaScript部分怎么写。
JavaScript
我们将使用Snap.svg,一个同SVG一起工作的强大的类库。为了更好地理解它的用法,请查看documentation和interactive Getting Started tutorial。
让我们从定义变量speed和easing开始。我们也将定义一个变量,它会包含路径及其hover状态的信息。当锚点处于hover状态时,路径会动态变为“to”路径。当脱离hover状态时,动态变回“from”路径:
(function() {
function init() {
var speed = 250,
easing = mina.easeinout;
[].slice.call ( document.querySelectorAll( '#grid > a' ) ).forEach( function( el ) {
var s = Snap( el.querySelector( 'svg' ) ), path = s.select( 'path' ),
pathConfig = {
from : path.attr( 'd' ),
to : el.getAttribute( 'data-path-hover' )
};
el.addEventListener( 'mouseenter', function() {
path.animate( { 'path' : pathConfig.to }, speed, easing );
} );
el.addEventListener( 'mouseleave', function() {
path.animate( { 'path' : pathConfig.from }, speed, easing );
} );
} );
}
init();
})();
以上就是全部内容了!我们已经向大家展示了三个示例,但是除此之外仍然会有很多的酷炫图形和动态、颜色效果。
希望你能享受其中,并且产生了更多的启发与灵感!
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
关于韩聪
中标软件开源社区部项目助理,爱生活,略迷茫,在web前端攻城狮的道路上匍匐前进。个人博客、新浪微博,追梦的旅途中,愿与你同行。
如需转载烦请注明出处:
英文原文:http://tympanus.net/codrops/2014/01/07/shape-hover-effect-with-svg/
中文译文:https://www.fedev.cn/css3/shape-hover-effect-with-svg.html
Off White X Vapormax Flair