如果你曾经访问过新版的Christmas Experiments网站,那么你一定被网站上的日历效果所吸引。今天我们将和大家一起来研究如何使用SVG和Snap.svg来实现这种效果。思路是用svg创建一个带标题的背景,然后在鼠标hover的时候使它变形为另一种形状。有很多可行的方案来制作它,今天我们将创建三种不同的效果。利用SVG的好处是,我们可以任意调整它在父容器中的大小,将它们做成流式布局。
HTML结构:
我们要做的第一件事是什么呢?应该先用矢量软件制作一个矢量图形。可以用Adobe Illustrator或者Inkscape。每个图形都包含一条路径,我们需要使用它四个角的坐标来完成svg。这里我们将一个矩形转换为路径,如果你使用Inkscape,你可以将整个图形选中,然后选择Path > Object to Path,点的坐标可以在Edit > XML Editor中得到…,可以参考下面的截图:
html结构我们使用一个section
,给它加上class grid
,然后在其下放置a
标签,并在a
标签中放入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" ></ path ></ svg > < figcaption > < h2 >Crystalline</ h2 > < p >Soko radicchio bunya nuts gram dulse.</ p > < button >View</ button > </ figcaption > </ figure > </ a > <!-- ... --> </ section > |
每个SVG将有自己的viewBox
值,并将preserveAspectRatio
设置为none。
这将使我们能够将形状调整和拉伸到我们想要的尺寸。我们将在样式表中定义它的宽度和高度。鼠标hover时图形的信息将保存在data-path-hover
中。
CSS样式:
注意:下面的css没有包含各个厂商的前缀。
这些样式将被三种效果使用。首先写通用样式,然后在为每种效果写自己的样式。
先从grid
开始,让它居中,并给它一个max-width
和一个百分比的宽度,使它具有响应性。
.grid { margin : 40px auto 120px ; max-width : 1000px ; width : 90% ; } |
a
元素要左浮动,我们给它一个最大宽度250px,并给它一个25%的实际宽度,这样一行能放4张图片,并且是响应式的。我们后面还要处理小屏幕(平板和手机)的问题。
.grid a { float : left ; max-width : 250px ; width : 25% ; color : #333 ; } |
为了给奇数的图片一些偏移,我们设置顶部的margin 30px,底部的amrgin -30px,这将做出一个很好看的网格,就像Christmas Experiments网站上的那样。
.grid a:nth-child(odd) { margin : 30px 0 -30px 0 ; } |
figure
要设置为相对定位,因为我们需要设置它的一些子元素为绝对定位。由于鼠标悬停效果可能会导致一些溢出,所以我们要设置overflow
为“hidden”。
.grid figure { position : relative ; overflow : hidden ; margin : 5px ; background : #333 ; } |
图片要和它的父元素一样宽,透明度设置为0.7左右。当鼠标hover的时候我们希望透明度有所变化,所以加上个transition。
.grid figure img { position : relative ; display : block ; width : 100% ; opacity : 0.7 ; transition : opacity 0.3 s; } |
figcaption
需要绝对定位,并且宽度和高度都设置为100%。
.grid figcaption { position : absolute ; top : 0 ; z-index : 11 ; padding : 10px ; width : 100% ; height : 100% ; text-align : center ; } |
h2
和p
元素在鼠标hover时都会运动,所以我们分别给他们设置transitions。
.grid figcaption h 2 { margin : 0 0 20px 0 ; color : #3498db ; text-transform : uppercase ; letter-spacing : 1px ; font-weight : 300 ; font-size : 130% ; transition : transform 0.3 s; } .grid figcaption p { padding : 0 20px ; color : #aaa ; font-weight : 300 ; transition : opacity 0.3 s, transform 0.3 s; } .grid figcaption h 2 , .grid figcaption p { transform : translateY ( 50px ); } |
所有效果中的按钮样式都是一样的。按钮在hover时也有一些动画,所以添加一个transition来改变它的透明度和动画效果。
.grid figure button { position : absolute ; padding : 4px 20px ; border : none ; text-transform : uppercase ; letter-spacing : 1px ; font-weight : bold ; transition : opacity 0.3 s, transform 0.3 s; } |
为了避免一些闪烁和抖动,我们需要将所有的动画元素和它们的父元素的backface-visibility
设置为hidden。
.grid figcaption, .grid figcaption h 2 , .grid figcaption p, .grid figure button { backface-visibility : hidden ; } |
SVG也应该是绝对定位的,并将它的宽和高设置为100%,在Firefox26.0中顶部定位会有一些偏差,所以我们给它的top
设置为-1px来修补这个bug。
.grid svg { position : absolute ; top : -1px ; /* fixes rendering issue in FF */ z-index : 10 ; width : 100% ; height : 100% ; } |
使用白色来填充图形的路径。
.grid svg path { fill: #fff ; } |
通用的鼠标hover效果应该像下边这样:
.grid a:hover figure img { opacity : 1 ; } .grid a:hover figcaption h 2 , .grid a:hover figcaption p { transform : translateY ( 0 ); } .grid a:hover figcaption p { opacity : 0 ; } |
当标题上升到指定位置后,图片的透明度应该设置为1。
现在,让我们来为每种效果制作各自的样式。
在第一种效果中,我们希望按钮有白色的边并且居中。在最开始的时候它是隐藏和缩小的。我们使用transforms来定位它,并使它缩小,当鼠标hover的时候,我们将使按钮慢慢放大。
.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 ); } |
在第二种效果中,我们定义了其它一些颜色来使按钮隐藏在figure
下面。我们设置它的bottom
为0,然后translate它到100%,当鼠标hover的时候,我们将它的上升效果设置为“ease-out”。
.demo -2 body { background : #e74c3c ; } .demo -2 .grid figcaption h 2 { color : #e74c3c ; } .demo -2 .grid figcaption p { transition-delay : 0.05 s; } .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”效果,这将有助于模拟弹性过渡,当鼠标悬停的时候我们设置段落的延时为0,这将能确保党SVG图形到达顶部时段落能很快的消失。
.demo -2 .grid figcaption h 2 , .demo -2 .grid figcaption p, .demo -3 .grid figcaption h 2 , .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 : 0 s; transition-duration : 0.1 s; } |
第三种效果我们将改变一些颜色,在鼠标hover时将标题translate一点,而不是设为0。
.demo -3 body { background : #52be7f ; } .demo -3 .grid figcaption h 2 { color : #52be7f ; } .demo -3 .grid a:hover figcaption h 2 { transform : translateY ( 5px ); } |
对于小屏幕,我们要改变每行显示的图片数量,我们将重置宽度和奇数子元素的margin,第2、5、8、11个a
元素要设置一个margin,可以通过nth-child(3n-1)
来实现。
小提示:如果你想快速的找到某种序列的表达式,你可以到WolframAlpha去输入你的序列,它能很快的计算出该序列的表达式。
对于更小尺寸的屏幕,我们将通过设置max-width
和标题的margins来控制它。
@media screen and ( max-width : 58em ) { .grid a { width : 33.333% ; } .grid a:nth-child(odd) { margin : 0 ; } .grid a:nth-child( 3 n -1 ) { margin : 30px 0 -30px 0 ; } } @media screen and ( max-width : 45em ) { .grid { max-width : 500px ; } .grid a { width : 50% ; } .grid a:nth-child( 3 n -1 ) { margin : 0 ; } .grid a:nth-child(even) { margin : 30px 0 -30px 0 ; } .grid figcaption h 2 { 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 ; } } |
JAVASCRIPT
我们将使用Snap.svg,它是一个很棒的SVGs库,要想知道它是如何工作的,请先看一下它的文档和入门教程。
我们先设置speed和easing的值,然后创建一个变量来保存路径上的信息和悬停的路径。当鼠标悬停的时候,我们将动画路径转变为“to”状态,鼠标离开时,将动画转变为“form”状态。
( 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(); })(); |
网盘下载密码:y82r