Гибкие SVG элементы

Мери Лу

Оригинал: http://tympanus.net/codrops/2014/12/15/elastic-svg-elements/

Перевод: Влад Мержевич

Демонстрация

Скачать исходники

Сегодня мы хотели бы поделиться некоторыми мыслями по добавлению гибкости к элементам. Идея в том, чтобы интегрировать SVG элемент в компонент, а затем оживить переход одной кривой в другую с помощью анимации. Использование SVG для таких вещей как меню, кнопки и другие элементы делает их более интересными, а взаимодействие с ними естественным и органичным. Конечно, важно сохранить в них изящество без чрезмерной упругости. Приятно то, что мы можем дать более «реалистичную» интерактивную обратную связь с пользователем. Особую выгоду от такого эффекта можно извлечь при взаимодействии с сенсорным экраном. Опираясь на эту идею мы создали несколько впечатляющих примеров, в которых анимированное изменение формы имеет смысл.

Для анимации SVG мы используем Snap.svg — превосходную библиотеку JavaScript для современных браузеров.

Иконки, которые применяются в некоторых демонстрациях, взяты из одного набора иконок  Font Awesome от Дэйва Ганди.

Для демонстрации перетаскивания элементов мы используем  Dragabilly  от Дэвида ДеСандро.

Пожалуйста, обратите внимание, что всё это является экспериментальным и демонстрации были проверены только в последних версиях современных браузеров.

Пример того, как мы используем SVG в компонентах (боковое меню в данном случае), следующий:

<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>

SVG вставляется после вложенного меню и мы задействуем два атрибута data для хранения анимируемых в дальнейшем кривых, в зависимости от того, открыто или закрыто меню.

SVG добавляется в меню абсолютно, при этом должно быть достаточно пустого пространства по бокам чтобы мы видели движение гибкой линии без её обрезания. Обратите внимание, что SVG занимает ширину и высоту 100% и не сохраняет исходные пропорции. Это важно для некоторых форм, у которых, возможно, вы захотите сохранить заданные пропорции и сделать растяжение только в одном направлении. Для этого примера мы установили фиксированную ширину для обёртки формы.

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

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

Через Snap.svg мы затем можем сделать переход одной формы в другую.

(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' ) );

})();

С правильно заданной функцией времени и уместным временем анимации получим упругое естественное движение. Но варианты настолько изменчивы и зависят от используемого контекста, что возможности просто безграничны.

Надеемся, вам понравились эти маленькие эффекты и вы нашли их вдохновляющими!

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.