Inspiration for Dialog Effects

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.
Dialog Effects

From our weekly sponsor: Design every part of your website with the brand new Divi Theme Builder. Try it for free.

Last year we posted some inspiration for modal window effects and today we’d like to share some fresh ideas with you. Styles and trends change and this calls for different effects that fit to a modern UI. This new set contains some subtle animations and also some more fancy SVG morphing techniques for dialogs.

Please note that this was tested in latest browser versions only.

Please also note that IE11 does not seem to support vieport units in calc() which we use in some of the animation transforms.

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>

Note that in the future we’ll be able to use the native <dialog> element. But currently support is still very weak, with IE, Firefox and Safari not supporting it.

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); }
}

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

})();

There seems to be some kind of stacking problem in Safari with the perspective effects. Read more about it here: Weird CSS Rotation Animation Glitch in Safari

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

Tagged with:

Mary Lou

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

http://www.codrops.com

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

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 70

Comments are closed.
  1. Awesome awesome as always!

    Call function for multiple dialog windows

    (function() {
    $(‘[data-dialog]’).each( function(){
    var dlgtrigger = this,
    somedialog = document.getElementById( dlgtrigger.getAttribute( ‘data-dialog’ ) ),
    dlg = new DialogFx( somedialog );

    dlgtrigger.addEventListener( ‘click’, dlg.toggle.bind(dlg) );
    });
    })();

  2. Top Work πŸ™‚
    Also, really great to see you have embraced BEM. You just increased your awesomeness even more πŸ™‚ (that’s a whole lot of awesomeness btw)

  3. Hi, is this possible to load the dialog box without having trigger click? so when page is initially load the dialog box will appear.

    Thanks much..

  4. Multiple dialogues really sounds like awesome ……..inspired though this little things….great and thanks

  5. Thanks for these dialogs! When implementing these, however, I ran into a problem. I tweaked the call to have multiple boxes using code almost identical to Samuel’s, but when I call this from a JS function instead of inside HTML, it takes two clicks of the trigger button to have the dialog pop up, then the dialog appears twice. Is this something I can easily tweak to fix?
    Thanks!

  6. Hi guys,
    for multiple buttons/dialogs:

    ...
    <div class="button-wrap"><button data-dialog="somedialog-1" class="trigger">Open Dialog</button></div>
    <div class="button-wrap"><button data-dialog="somedialog-2" class="trigger">Open Dialog</button></div>
    ...
    <div id="somedialog-1" 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>
    
    <div id="somedialog-2" class="dialog">
    	<div class="dialog__overlay"></div>
    	<div class="dialog__content">
    		<h2><strong>Howdy</strong>, I'm another dialog box</h2><div><button class="action" data-dialog-close>Close</button></div>
    	</div>
    </div>
    ...
    
    (function() {
    
    	[].slice.call( document.querySelectorAll( '[data-dialog]' ) ).forEach( function( trigger ) {
    		var dlg = new DialogFx( document.getElementById( trigger.getAttribute( 'data-dialog' ) ) );
    
    		trigger.addEventListener( 'click', dlg.toggle.bind(dlg) );
    	} );
    
    })();
    
    • Dear Pedro Botelho,
      You forgot to mention the following lines in the code above.

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

    • This works on multiple windows, but i have an issue. I’ve added inside the code so i can stop a playing video when the modal is closed.
      It works on the first element, but not on the rest.


      onEndAnimation(this.el.querySelector('.dialog__content'), function () {
      classie.remove(self.el, 'dialog--close');

      var video = $("#videoStop").attr("src"); //added
      $("#videoStop").attr("src", ""); //added
      $("#videoStop").attr("src", video); //added

      });

    • You are awesome! πŸ™‚ Thanks, that fixed using multiple dialogs for me!

  7. Great Tut. One of the best modal boxes tut i have ever encountered. Simple yet beautiful.
    Would love to see more from you.
    regards