Material Design inspired modals. No jQuery required. Responsive. Read the how to on Ettrics.com
Created
March 28, 2016 06:56
-
-
Save jahidHn/c99a37b4e16a6068fe52 to your computer and use it in GitHub Desktop.
Responsive Modal Design
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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.<br><a href="http://ettrics.com/code/material-design-modal/" target="_blank" class="link">Read the how-to on Ettrics.com</a></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="http://ettrics.com/code/material-design-modal/" class="logo" target="_blank"> | |
<img class="logo" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/45226/ettrics-logo.svg" alt="" /> | |
</a> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$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 'Roboto' | |
-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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment