Skip to content

Instantly share code, notes, and snippets.

@Polarhardboiled
Created August 26, 2021 07:02
Show Gist options
  • Save Polarhardboiled/a860012818c14f366e2cd1fe91e3a1be to your computer and use it in GitHub Desktop.
Save Polarhardboiled/a860012818c14f366e2cd1fe91e3a1be to your computer and use it in GitHub Desktop.
Responsive Modal Design
<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>

Responsive Modal Design

Material Design inspired modals. No jQuery required. Responsive. Read the how to on Ettrics.com

A Pen by Polarhardboiled on CodePen.

License.

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();
$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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment