前端开发whqet,csdn,王海庆,whqet,前端开发专家
效果预览
众所周知,flash动画类型可以分为补间动画和逐帧动画,补间动画又可以分为属性改变(大小、位置、颜色等)和形状改变(直线变弧线等)。网页动画里,我们可以使用css3、javascript(jquery)等实现属性改变,却对形状改变无能为力,那么如何实现网页动画里的形状改变呢?今天提供一种解决方案——通过snap.svg动态改变svg形状实现,案例效果如下图所示,案例灵感来自codrops。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmL4kzN381M5QzM1kTOxQTMvwFMz8CXyEDNxAjMvw1ckF2bsBXdvwFdl5mLuR2cj5Set1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
----------------
----------------------------------------
在线研究点击这里,下载收藏点击这里。
----------------------------------------
---------------
关键技术
制作这个案例,你需要
1. snap.svg的基本使用
2. classie.js的基本使用
3. snap.svg操作改变svg的内容
4. 冲动与激情
实现步骤
ok,我们html内容如下,.menu为整个容器,.menu__handle为单击按钮,.menu__inner为弹出菜单内容,.morph-shape为形状改变的线条。我们把需要改变的线条的path数据实现放到data-morph-open和data-morph-close两个属性里。
<div class="container">
<nav id="menu" class="menu">
<button class="menu__handle"><span>Menu</span></button>
<div class="menu__inner">
<ul>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Home</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Favs</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Files</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >Stats</li>
</ul>
</div>
<div class="morph-shape" data-morph-open="M300-10c0,0,295,164,295,410c0,232-295,410-295,410" data-morph-close="M300-10C300-10,5,154,5,400c0,232,295,410,295,410">
<svg width="100%" height="100%" viewBox="0 0 600 800" preserveAspectRatio="none">
<path fill="none" d="M300-10c0,0,0,164,0,410c0,232,0,410,0,410"/>
</svg>
</div>
</nav>
</div>
然后是css,css里面我们实现基本布局与css3动画。css里面我们使用了Normalize和prefixfree。按钮(三条线变成x)由.menu__handle的before、after两个伪对象和span实现。
/*统一化设置*/
*, *:after, *:before { box-sizing: border-box; }
.clearfix:before, .clearfix:after { content: ''; display: table; }
.clearfix:after { clear: both; }
body {
color: #fff;
background: #FF7F50;
font-weight: 400;
font-size: 1em;
}
a {
color: #fff;
text-decoration: none;
}
a:hover,
a:focus {
color: #393;
outline: none;
}
.container {
text-align: center;
padding: 5.25em 0.5em 0;
}
/*菜单设置*/
.menu {
position: fixed;
width: 240px;
top: 2px;
bottom: 2px;
left: 0;
z-index: 100;
overflow: hidden;
transform: translate3d(-150px, 0, 0);
transition: transform 0.6s;
}
.menu.menu--open {
transform: translate3d(0, 0, 0);
}
.menu__inner {
width: calc(100% + 15px);
padding: 0 100px 2em 0;
overflow-y: auto;
height: 100%;
position: relative;
z-index: 100;
}
.menu ul {
list-style: none;
padding: 0;
margin: 0;
}
.menu ul li {
transform: translate3d(-150px, 50px, 0);
transition: transform 0.6s;
height:24px;
line-height:24px;
}
.menu.menu--anim ul li {
transform: translate3d(0, 0, 0);
}
.menu ul li:first-child {
transition-delay: 0.3s;
}
.menu ul li:nth-child(2) {
transition-delay: 0.2s;
}
.menu ul li:nth-child(3) {
transition-delay: 0.1s;
}
.menu ul li a {
display: block;
outline: none;
}
/*按钮及单击之后变换*/
.menu__handle {
background: #FF7F50;
border: none;
width: 30px;
height: 24px;
padding: 0;
outline: none;
position: absolute;
top: 3px;
right: 45px;
z-index: 2000;
}
.menu__handle::before,
.menu__handle::after,
.menu__handle span {
background: #fff;
}
.menu__handle::before,
.menu__handle::after {
content: '';
position: absolute;
height: 2px;
width: 100%;
left: 0;
top: 50%;
transform-origin: 50% 50%;
transition: transform 0.25s;
}
.menu__handle span {
position: absolute;
width: 100%;
height: 2px;
left: 0;
overflow: hidden;
text-indent: 200%;
transition: opacity 0.25s;
}
.menu__handle::before {
transform: translate3d(0, -10px, 0);
}
.menu__handle::after {
transform: translate3d(0, 10px, 0);
}
.menu--open .menu__handle span {
opacity: 0;
}
.menu--open .menu__handle::before {
transform: rotate3d(0, 0, 1, 45deg);
}
.menu--open .menu__handle::after {
transform: rotate3d(0, 0, 1, -45deg);
}
/* 线条及改变 */
.morph-shape {
position: absolute;
width: 160px;
height: 100%;
top: 0;
right: 0px;
}
.morph-shape svg path {
stroke: #fff;
stroke-width: 2px;
}
.menu--open .morph-shape svg path {
stroke: #fff;
stroke-width: 4px;
}
然后是javascript,也是我们的核心。这里用到了classie.js和snap.svg(可以参考张鑫旭大侠翻译的snap.svg中文版)。
function SVGMenu( el, options ) {
this.el = el;
this.init();
}
SVGMenu.prototype.init = function() {
this.trigger = this.el.querySelector( 'button.menu__handle' );
this.shapeEl = this.el.querySelector( 'div.morph-shape' );
var s = Snap( this.shapeEl.querySelector( 'svg' ) );
this.pathEl = s.select( 'path' );
this.paths = {
reset : this.pathEl.attr( 'd' ),
open : this.shapeEl.getAttribute( 'data-morph-open' ),
close : this.shapeEl.getAttribute( 'data-morph-close' )
};
this.isOpen = false;
this.trigger.addEventListener( 'click', this.toggle.bind(this) );
};
SVGMenu.prototype.toggle = function() {
var self = this;
if( this.isOpen ) {
classie.remove( self.el, 'menu--anim' );
setTimeout( function() { classie.remove( self.el, 'menu--open' ); }, 250 );
}
else {
classie.add( self.el, 'menu--anim' );
setTimeout( function() { classie.add( self.el, 'menu--open' ); }, 250 );
}
self.pathEl.stop().animate( { 'path' : self.isOpen ? self.paths.close : this.paths.open }, 350, mina.easeout, function() {
self.pathEl.stop().animate( { 'path' : self.paths.reset }, 800, mina.elastic );
} );
self.isOpen = !self.isOpen;
};
new SVGMenu( document.getElementById( 'menu' ) );
ok,请大家仔细揣摩。当然,这个方面也出了一些插件可以使用例如,SVG Morpheus,也可看看《SVG-Morpheus实现SVG图标图形间的补形动画》这篇教程。
----------------------------------------------------------
前端开发whqet,关注web前端开发,分享相关资源,欢迎点赞,欢迎拍砖。
---------------------------------------------------------------------------------------------------------