<div class="demo-btns">
		<header>
			<h1>Material Design Modals</h1>
		</header>

		<div class="info">
			<div class="buttons">
				<p>
					<a href="" data-modal="#modal" class="modal__trigger">Modal 1</a>
					<a href="" data-modal="#modal2" class="modal__trigger">Modal 2</a>
					<a href="" data-modal="#modal3" class="modal__trigger">Modal 3</a>
				</p>
			</div>
			<p>Click a button to activate a modal.</p>
		</div>
	</div>

	<!-- Modal -->
	<div id="modal" class="modal modal__bg" role="dialog" aria-hidden="true">
		<div class="modal__dialog">
			<div class="modal__content">
				<h1>Modal</h1>
				<p>Church-key American Apparel trust fund, cardigan mlkshk small batch Godard mustache pickled bespoke meh seitan. Wes Anderson farm-to-table vegan, kitsch Carles 8-bit gastropub paleo YOLO jean shorts health goth lo-fi. Normcore chambray locavore Banksy, YOLO meditation master cleanse readymade Bushwick.</p>
				
				<!-- modal close button -->
				<a href="" class="modal__close demo-close">
					<svg class="" viewBox="0 0 24 24"><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/><path d="M0 0h24v24h-24z" fill="none"/></svg>
				</a>
				
			</div>
		</div>
	</div>

	<div id="modal2" class="modal modal--align-top modal__bg" role="dialog" aria-hidden="true">
		<div class="modal__dialog">
			<div class="modal__content">
				<h1>Big Modal</h1>
				<h3>This modal is pretty tall.</h3>
				<p>Selfies normcore four dollar toast four loko listicle artisan. Hoodie Marfa authentic, wayfarers church-key tofu Banksy pop-up Kickstarter Brooklyn heirloom swag synth. Echo Park cray synth mixtape. Tofu gastropub squid readymade, trust fund Wes Anderson DIY PBR 8-bit try-hard +1 Shoreditch lo-fi tote bag.</p>
				<p><img src="http://unsplash.it/600/300" alt="" /></p>
				<p>Mumblecore cred selfies fingerstache. Tousled skateboard plaid lo-fi shabby chic salvia, swag Odd Future Etsy art party Austin cronut. Crucifix whatever Pinterest food truck, pickled viral cray 90's DIY chambray keffiyeh biodiesel Vice blog. Cred meh yr tofu.</p>
				<p>Mumblecore cred selfies fingerstache. Tousled skateboard plaid lo-fi shabby chic salvia, swag Odd Future Etsy art party Austin cronut. Crucifix whatever Pinterest food truck, pickled viral cray 90's DIY chambray keffiyeh biodiesel Vice blog. Cred meh yr tofu.</p>
				<!-- modal close button -->
				<a href="" class="modal__close demo-close">
					<svg class="" viewBox="0 0 24 24"><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/><path d="M0 0h24v24h-24z" fill="none"/></svg>
				</a>
			</div>
		</div>
	</div>

	<div id="modal3" class="modal modal__bg" role="dialog" aria-hidden="true">
		<div class="modal__dialog">
			<div class="modal__content">
				<h1>Modal 3</h1>
				<p>Church-key American Apparel trust fund, cardigan mlkshk small batch Godard mustache pickled bespoke meh seitan. Wes Anderson farm-to-table vegan, kitsch Carles 8-bit gastropub paleo YOLO jean shorts health goth lo-fi.</p>
				
				<!-- modal close button -->
				<a href="" class="modal__close demo-close">
					<svg class="" viewBox="0 0 24 24"><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/><path d="M0 0h24v24h-24z" fill="none"/></svg>
				</a>
			</div>
		</div>
	</div>

	<!-- Ettrics -->
	<a href="https://ettrics.com/" class="logo" target="_blank">
	 <img class="logo" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/45226/ettrics-logo.svg" alt="" /> 
	</a>
$modal-z = 1000
$modal-bg = #FFEBEE
$modal-width = 600px

$space = 2.4rem
$red = #F44336

$t = .5s

$ease($s = $t)
	transition all $s cubic-bezier(0.23, 1, 0.32, 1)

*
	box-sizing border-box

body
	line-height 1.5
	font-family 'Lato'
	-webkit-font-smoothing antialiased
	overflow-x hidden

h1, h2, h3, p
	font-weight 300
	margin 0 0 ($space) 0

h1, h2, h3
	line-height 1.3

a
	text-decoration none
	color inherit
	font-weight 400

/**
 * Material Modal CSS
 */

.modal
	will-change visibility, opacity
	display flex
	align-items center
	justify-content center
	position fixed
	top 0
	left 0
	right 0
	bottom 0
	overflow-y auto
	overflow-x hidden
	z-index $modal-z
	// hide modal
	visibility hidden
	opacity 0
	$ease()
	transition-delay $modal-delay

	&--active
		// reveal modal
		visibility visible
		opacity 1

	&--align-top
		// align to top of window, useful if modal has a lot of content
		align-items flex-start

	&__bg
		// background color can be added as a backdrop for the modal
		background transparent

	&__dialog
		// controls the width and padding of modal
		max-width $modal-width
		padding ($space / 2)

	&__content
		will-change transform, opacity
		position relative
		padding $space
		background $modal-bg
		background-clip padding-box
		box-shadow 0 12px 15px 0 rgba(black, 0.25)
		opacity 0
		$ease(.25s)

		&--active
			opacity 1

	&__close
		z-index $modal-z+100
		cursor pointer

	&__trigger
		// modal trigger button
		position relative
		display inline-block;
		padding ($space / 2) $space
		color: rgba(black, 0.7)
		line-height 1
		cursor pointer
		background $modal-bg
		box-shadow 0 2px 5px 0 rgba(black, 0.26)
		-webkit-tap-highlight-color: rgba(0,0,0,0);		user-select none
		$ease()

		&--active
				z-index 10

		&:hover
				background mix(black, $modal-bg, 10)


#modal__temp
	// this is the div that expands when the button is clicked
	will-change transform, opacity
	position absolute
	top 0
	left 0
	right 0
	bottom 0
	background $modal-bg
	transform none
	opacity 1
	transition opacity 0.1s ease-out, transform $t cubic-bezier(0.23, 1, 0.32, 1)

/**
 * Demo specific CSS
 */

body
	height 100vh
	background $red

img
	max-width 100%

.demo-btns

	header
		padding 7vh 10vw
		background $modal-bg
		display flex
		align-items center

		h1
			margin 0
			color rgba(black, 0.54)
			font-weight 300

	.info
		background $red
		padding 3vh 10vw
		height 70vh
		display flex
		align-items center
		justify-content center
		flex-flow column wrap

	p
		text-align: center
		color white

	.link
		font-size 20px

	.modal__trigger
		margin-right 3px
		@media (max-width 640px)
			margin-bottom ($space / 3)

.demo-close
	position absolute
	top 0
	right 0
	margin: ($space / 2)
	padding: ($space / 4)
	background rgba(black, 0.3)
	border-radius 50%
	$ease()

	svg
		width 24px
		fill: white
		pointer-events none
		vertical-align top

	&:hover
		background rgba(black, 0.6);

.logo
	position: fixed
	bottom: 3vh
	right: 3vw
	z-index: 2

	img
		width: 45px
		transform: rotate(0)
		$ease()

		&:hover
			transform: rotate(180deg) scale(1.1)
View Compiled
var Modal = (function() {

  var trigger = $qsa('.modal__trigger'); // what you click to activate the modal
  var modals = $qsa('.modal'); // the entire modal (takes up entire window)
  var modalsbg = $qsa('.modal__bg'); // the entire modal (takes up entire window)
  var content = $qsa('.modal__content'); // the inner content of the modal
	var closers = $qsa('.modal__close'); // an element used to close the modal
  var w = window;
  var isOpen = false;
	var contentDelay = 400; // duration after you click the button and wait for the content to show
  var len = trigger.length;

  // make it easier for yourself by not having to type as much to select an element
  function $qsa(el) {
    return document.querySelectorAll(el);
  }

  var getId = function(event) {

    event.preventDefault();
    var self = this;
    // get the value of the data-modal attribute from the button
    var modalId = self.dataset.modal;
    var len = modalId.length;
    // remove the '#' from the string
    var modalIdTrimmed = modalId.substring(1, len);
    // select the modal we want to activate
    var modal = document.getElementById(modalIdTrimmed);
    // execute function that creates the temporary expanding div
    makeDiv(self, modal);
  };

  var makeDiv = function(self, modal) {

    var fakediv = document.getElementById('modal__temp');

    /**
     * if there isn't a 'fakediv', create one and append it to the button that was
     * clicked. after that execute the function 'moveTrig' which handles the animations.
     */

    if (fakediv === null) {
      var div = document.createElement('div');
      div.id = 'modal__temp';
      self.appendChild(div);
      moveTrig(self, modal, div);
    }
  };

  var moveTrig = function(trig, modal, div) {
    var trigProps = trig.getBoundingClientRect();
    var m = modal;
    var mProps = m.querySelector('.modal__content').getBoundingClientRect();
    var transX, transY, scaleX, scaleY;
    var xc = w.innerWidth / 2;
    var yc = w.innerHeight / 2;

    // this class increases z-index value so the button goes overtop the other buttons
    trig.classList.add('modal__trigger--active');

    // these values are used for scale the temporary div to the same size as the modal
    scaleX = mProps.width / trigProps.width;
    scaleY = mProps.height / trigProps.height;

    scaleX = scaleX.toFixed(3); // round to 3 decimal places
    scaleY = scaleY.toFixed(3);


    // these values are used to move the button to the center of the window
    transX = Math.round(xc - trigProps.left - trigProps.width / 2);
    transY = Math.round(yc - trigProps.top - trigProps.height / 2);

		// if the modal is aligned to the top then move the button to the center-y of the modal instead of the window
    if (m.classList.contains('modal--align-top')) {
      transY = Math.round(mProps.height / 2 + mProps.top - trigProps.top - trigProps.height / 2);
    }


		// translate button to center of screen
		trig.style.transform = 'translate(' + transX + 'px, ' + transY + 'px)';
		trig.style.webkitTransform = 'translate(' + transX + 'px, ' + transY + 'px)';
		// expand temporary div to the same size as the modal
		div.style.transform = 'scale(' + scaleX + ',' + scaleY + ')';
		div.style.webkitTransform = 'scale(' + scaleX + ',' + scaleY + ')';


		window.setTimeout(function() {
			window.requestAnimationFrame(function() {
				open(m, div);
			});
		}, contentDelay);

  };

  var open = function(m, div) {

    if (!isOpen) {
      // select the content inside the modal
      var content = m.querySelector('.modal__content');
      // reveal the modal
      m.classList.add('modal--active');
      // reveal the modal content
      content.classList.add('modal__content--active');

      /**
       * when the modal content is finished transitioning, fadeout the temporary
       * expanding div so when the window resizes it isn't visible ( it doesn't
       * move with the window).
       */

      content.addEventListener('transitionend', hideDiv, false);

      isOpen = true;
    }

    function hideDiv() {
      // fadeout div so that it can't be seen when the window is resized
      div.style.opacity = '0';
      content.removeEventListener('transitionend', hideDiv, false);
    }
  };

  var close = function(event) {

		event.preventDefault();
    event.stopImmediatePropagation();

    var target = event.target;
    var div = document.getElementById('modal__temp');

    /**
     * make sure the modal__bg or modal__close was clicked, we don't want to be able to click
     * inside the modal and have it close.
     */

    if (isOpen && target.classList.contains('modal__bg') || target.classList.contains('modal__close')) {

      // make the hidden div visible again and remove the transforms so it scales back to its original size
      div.style.opacity = '1';
      div.removeAttribute('style');

			/**
			* iterate through the modals and modal contents and triggers to remove their active classes.
      * remove the inline css from the trigger to move it back into its original position.
			*/

			for (var i = 0; i < len; i++) {
				modals[i].classList.remove('modal--active');
				content[i].classList.remove('modal__content--active');
				trigger[i].style.transform = 'none';
        trigger[i].style.webkitTransform = 'none';
				trigger[i].classList.remove('modal__trigger--active');
			}

      // when the temporary div is opacity:1 again, we want to remove it from the dom
			div.addEventListener('transitionend', removeDiv, false);

      isOpen = false;

    }

    function removeDiv() {
      setTimeout(function() {
        window.requestAnimationFrame(function() {
          // remove the temp div from the dom with a slight delay so the animation looks good
          div.remove();
        });
      }, contentDelay - 50);
    }

  };

  var bindActions = function() {
    for (var i = 0; i < len; i++) {
      trigger[i].addEventListener('click', getId, false);
      closers[i].addEventListener('click', close, false);
      modalsbg[i].addEventListener('click', close, false);
    }
  };

  var init = function() {
    bindActions();
  };

  return {
    init: init
  };

}());

Modal.init();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.