Elastic SVG Elements

Some inspiration for elastic components with SVG shape animations for enhanced UI interactions.

Today we’d like to share some inspiration for adding elasticity to elements. The idea is to integrate an SVG element into a component and then animate it from one path to another with an elastic animation. Using SVGs like this can make things like menus, buttons or other elements more interesting and make the interaction look more organic with a natural feel to it. It’s of course important to keep things subtle and not exaggerate the bounciness. The nice thing is that we can give a more “realistic” interaction feedback to the user. Especially touch feedback can benefit from using this kind of effect. Based on this idea, we’ve created some inspirational examples of contexts where a morphing shape animation enhancement could make sense.

For animating the SVGs, we use Snap.svg, the excellent JavaScript SVG library for modern browsers.

The icons used in some of the demos are from the one and only Font Awesome icon set by Dave Gandy.

For the demo with the draggable & droppable elements we use Dragabilly by David DeSandro.

Please note that this is highly experimental and the demos were only tested in the latest versions of modern browsers.

An example of how we use the SVGs in the components (the sidebar menu in this case) is the following:

<nav id="menu" class="menu">
	<button class="menu__handle"><span>Menu</span></button>
	<div class="menu__inner">
		<ul>
			<li><a href="#"><i class="fa fa-fw fa-home"></i><span>Home<span></a></li>
			<li><a href="#"><i class="fa fa-fw fa-heart"></i><span>Favs<span></a></li>
			<li><a href="#"><i class="fa fa-fw fa-folder"></i><span>Files<span></a></li>
			<li><a href="#"><i class="fa fa-fw fa-tachometer"></i><span>Stats<span></a></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>

The SVG is inserted after the inner menu and we use two data attributes to store the paths we will be animating the default path to (depending on whether we open or close the menu).

The SVG will be placed absolute into the menu, and enough spacing needs to be ensured on the sides so that we see the line moving elastically without getting cut off. Note that the SVGs are made responsive by using a width and height of 100% and not preserving the aspect ratio. This is important for some shapes as you might want to retain certain proportions and allow a stretching in one dimension only. For this example, although we always set the width and height to 100% in the HTML, we set a fixed width to the morph shape wrapper and the SVG:

.morph-shape {
	position: absolute;
	width: 240px;
	height: 100%;
	top: 0;
	right: 0;
}

.morph-shape svg path {
	stroke: #5f656f;
	stroke-width: 5px;
}

With Snap.svg we can then morph from one shape to another:

(function() {

	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.initEvents();
	};

	SVGMenu.prototype.initEvents = function() {
		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 );
		}
		this.pathEl.stop().animate( { 'path' : this.isOpen ? this.paths.close : this.paths.open }, 350, mina.easeout, function() {
			self.pathEl.stop().animate( { 'path' : self.paths.reset }, 800, mina.elastic );
		} );
		
		this.isOpen = !this.isOpen;
	};

	new SVGMenu( document.getElementById( 'menu' ) );

})();

With the right easing functions and appropriate timings, a slightly bouncy, organic movement can be created. But the options are so versatile and depend on the whole feel of a specific context, so the possibilities are endless 🙂

We hope you enjoy these little effects and find them inspiring!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.