Ads

Tuesday, 9 December 2014

Inspiration for dialog effects


Download   Demo
Inspiration for dialog effects is a small collection of dialog effects using CSS animations for your inspiration. Some effects use SVG animations of morphing paths with the help of Snap.svg.
1. HTML
For the dialog we use the following markup:
<div id="somedialog" class="dialog">
 <div class="dialog__overlay"></div>
 <div class="dialog__content">
  <h2><strong>Howdy</strong>, I'm a dialog box</h2><
  div><button class="action" data-dialog-close>Close</button></div>
 </div>
</div>
2. CSS
As you can see, we have a main dialog wrap which contains the overlay and the dialog content. The basic style for the dialog is the following (vendor prefixes are omitted):
.dialog,
.dialog__overlay {
 width: 100%;
 height: 100%;
 top: 0;
 left: 0;
}

.dialog {
 position: fixed;
 display: flex;
 align-items: center;
 justify-content: center;
 pointer-events: none;
}

.dialog__overlay {
 position: absolute;
 z-index: 1;
 background: rgba(55, 58, 71, 0.9);
 opacity: 0;
 transition: opacity 0.3s;
}

.dialog--open .dialog__overlay {
 opacity: 1;
 pointer-events: auto;
}

.dialog__content {
 width: 50%;
 max-width: 560px;
 min-width: 290px;
 background: #fff;
 padding: 4em;
 text-align: center;
 position: relative;
 z-index: 5;
 opacity: 0;
}

.dialog--open .dialog__content {
 pointer-events: auto;
}

/* Content */
.dialog h2 {
 margin: 0;
 font-weight: 400;
 font-size: 2em;
 padding: 0 0 2em;
 margin: 0;
}
We use flexbox on the main dialog element in order to center the dialog content. The overlay will appear with a transition. Please note that pointer events don’t work for IE < 11.
Some effects have an additional division for the inner content in order to hide it initially and fade it in after an effect of the modal is finished. This makes sense for effects that scale/distort the dialog.
An example for an effect (Sandra) is the following:
.dialog.dialog--open .dialog__content,
.dialog.dialog--close .dialog__content {
 animation-duration: 0.3s;
 animation-fill-mode: forwards;
}

.dialog.dialog--open .dialog__content {
 animation-name: anim-open;
}

.dialog.dialog--close .dialog__content {
 animation-name: anim-close;
}

@keyframes anim-open {
 0% { opacity: 0; transform: scale3d(1.1, 1.1, 1); }
 100% { opacity: 1; transform: scale3d(1, 1, 1); }
}

@keyframes anim-close {
 0% { opacity: 1; }
 100% { opacity: 0; transform: scale3d(0.9, 0.9, 1); }
}
3. JAVASCRIPT
With adding the dialog–open and dialog–close classes, we can control the appearing of the dialog and its inner elements.
The script for the dialog is the following:
;( function( window ) {
 
 'use strict';

 var support = { animations : Modernizr.cssanimations },
  animEndEventNames = { 'WebkitAnimation' : 'webkitAnimationEnd', 'OAnimation' : 'oAnimationEnd', 'msAnimation' : 'MSAnimationEnd', 'animation' : 'animationend' },
  animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ],
  onEndAnimation = function( el, callback ) {
   var onEndCallbackFn = function( ev ) {
    if( support.animations ) {
     if( ev.target != this ) return;
     this.removeEventListener( animEndEventName, onEndCallbackFn );
    }
    if( callback && typeof callback === 'function' ) { callback.call(); }
   };
   if( support.animations ) {
    el.addEventListener( animEndEventName, onEndCallbackFn );
   }
   else {
    onEndCallbackFn();
   }
  };

 function extend( a, b ) {
  for( var key in b ) { 
   if( b.hasOwnProperty( key ) ) {
    a[key] = b[key];
   }
  }
  return a;
 }

 function DialogFx( el, options ) {
  this.el = el;
  this.options = extend( {}, this.options );
  extend( this.options, options );
  this.ctrlClose = this.el.querySelector( '[data-dialog-close]' );
  this.isOpen = false;
  this._initEvents();
 }

 DialogFx.prototype.options = {
  // callbacks
  onOpenDialog : function() { return false; },
  onCloseDialog : function() { return false; }
 }

 DialogFx.prototype._initEvents = function() {
  var self = this;

  // close action
  this.ctrlClose.addEventListener( 'click', this.toggle.bind(this) );

  // esc key closes dialog
  document.addEventListener( 'keydown', function( ev ) {
   var keyCode = ev.keyCode || ev.which;
   if( keyCode === 27 && self.isOpen ) {
    self.toggle();
   }
  } );

  this.el.querySelector( '.dialog__overlay' ).addEventListener( 'click', this.toggle.bind(this) );
 }

 DialogFx.prototype.toggle = function() {
  var self = this;
  if( this.isOpen ) {
   classie.remove( this.el, 'dialog--open' );
   classie.add( self.el, 'dialog--close' );
   
   onEndAnimation( this.el.querySelector( '.dialog__content' ), function() {
    classie.remove( self.el, 'dialog--close' );
   } );

   // callback on close
   this.options.onCloseDialog( this );
  }
  else {
   classie.add( this.el, 'dialog--open' );

   // callback on open
   this.options.onOpenDialog( this );
  }
  this.isOpen = !this.isOpen;
 };

 // add to global namespace
 window.DialogFx = DialogFx;

})( window ); 
And we can call the dialog like this:
<script src="js/classie.js"></script>
<script src="js/dialogFx.js"></script>
<script>
 (function() {

  var dlgtrigger = document.querySelector( '[data-dialog]' ),
   somedialog = document.getElementById( dlgtrigger.getAttribute( 'data-dialog' ) ),
   dlg = new DialogFx( somedialog );

  dlgtrigger.addEventListener( 'click', dlg.toggle.bind(dlg) );

 })();
</script>
…where our trigger button has the data-attribute data-dialog=”somedialog”.
For the SVG effects (except the line drawing of Wilma) we use Snap.svg to morph SVG paths. We add the SVG shape into a wrap right into the dialog content and then we define the path to morph to in data-morph-open.

(function() {

 var dlgtrigger = document.querySelector( '[data-dialog]' ),

  somedialog = document.getElementById( dlgtrigger.getAttribute( 'data-dialog' ) ),
  // svg..
  morphEl = somedialog.querySelector( '.morph-shape' ),
  s = Snap( morphEl.querySelector( 'svg' ) ),
  path = s.select( 'path' ),
  initialPath = path.attr('d'),
  steps = { 
   open : morphEl.getAttribute( 'data-morph-open' )
  },
  dlg = new DialogFx( somedialog, {
   onOpenDialog : function( instance ) {
    // reset path
    morphEl.querySelector( 'svg > path' ).setAttribute( 'd', initialPath );
    // animate path
    path.stop().animate( { 'path' : steps.open }, 300, mina.easein );
   }
  } );

 dlgtrigger.addEventListener( 'click', dlg.toggle.bind(dlg) );

})();

No comments:

Post a Comment