在这篇教程里,我们将重新创建一个类似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(); })();
以上就是全部内容了!我们已经向大家展示了三个示例,但是除此之外仍然会有很多的酷炫图形和动态、颜色效果。