<header>
<nav class="navbar">
<ul class="menu">
<li class="menu-item">Home</li>
<li class="menu-item">Services</li>
<li class="menu-item">Contact</li>
</ul>
</nav>
</header>
<div class="container">
<button id="open-modal-1">Open Modal 1</button>
<button id="open-modal-2">Open Modal 2</button>
</div>
header {
align-items: center;
background-color: #3080B5;
display: flex;
height: 75px;
justify-content: center;
transition: background 0.3s ease;
&.modal-open {
background-color: #ffffff;
}
}
.menu {
align-items: center;
display: flex;
justify-content: center;
list-style: none;
}
.menu-item {
margin-right: 25px;
}
.container {
align-items: center;
background: #F7C02D;
display: flex;
flex-direction: column;
height: 100vh;
justify-content: center;
width: 100%;
}
.my-modal {
background: rgba(0,0,0, .5);
display: none;
height: 100%;
position: absolute;
top: 0;
left: 0;
width: 100%;
&.opened {
display: block;
}
&.closed {
display: none;
}
}
.my-modal-content {
padding: 30px;
position: absolute;
background-color: #fff;
height: 40%;
width: 40%;
text-align: center;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
h1 {
margin-top: 0;
}
}
#open-modal-1,
#open-modal-2 {
background: #3080B5;
border: 0;
border-radius: 3px;
color: #fff;
display: block;
margin-bottom: 30px;
padding: 20px 30px;
}
#close {
background: none;
border: none;
font-size: 24px;
position: absolute;
right: 10px;
top: 10px;
}
.animate-out {
animation: out 600ms ease-in-out forwards;
}
.animate-in {
animation: in 500ms ease-in-out forwards;
display: block;
}
@keyframes out {
0% {
transform: translate(-50%, -50%);
}
100% {
transform: translate(-50%, -200%);
}
}
@keyframes in {
0% {
opacity: 0;
transform: translate(-50%, -200%);
}
100% {
opacity: 1;
transform: translateX(-50%, -50%);
}
}
View Compiled
/**
* Modal Class
*/
class Modal {
/**
* Constructor
*
* @param openTrigger The element that will trigger opening the modal.
* @param options Options that will override defaults.
*/
constructor( openTrigger, options ) {
/**
* Configuration options.
*
* Merge any user defined options into default config.
*/
this.config = Object.assign( {
backgroundColor: '',
modalTitle: 'This is a modal!',
modalText: 'Default description text for modal.',
onBefore: null,
onAfter: null
}, options );
// Bind callback functions to the Modal.
this.config.onBefore = this.config.onBefore.bind( this );
this.config.onAfter = this.config.onAfter.bind( this );
// Set open trigger.
this.openTrigger = openTrigger;
// Set modal events.
this.bindEvents();
}
// Bind events.
bindEvents() {
this.openTrigger.addEventListener( 'click', this.open.bind( this ) );
}
// Open the modal.
open() {
this.render();
// Cache DOM.
this.modalDiv = document.getElementById( 'my-modal' );
this.myModalContent = document.querySelector( '.my-modal-content' );
// Bind close event.
this.modalDiv.addEventListener( 'click', this.close.bind( this ) );
// Call onBefore if it is defined.
if ( this.config.onBefore ) {
this.config.onBefore();
}
// Add classes.
this.modalDiv.classList.add( 'opened' );
this.myModalContent.classList.add( 'animate-in' );
// Remove animate class.
setTimeout( () => {
this.myModalContent.classList.remove( 'animate-in' )
}, 600 );
}
// Close the modal.
close( e ) {
// If we click the close button.
if ( e.target.id === 'close' && e.type === 'click' ) {
this.myModalContent.classList.add( 'animate-out' );
// Remove classes.
setTimeout( () => {
// Remove classes.
this.myModalContent.classList.remove( 'animate-out' );
this.modalDiv.classList.remove( 'opened' );
// Remove <div> from the DOM.
this.containerDiv.parentNode.removeChild( this.containerDiv );
// If onAfter is defined then call it.
if ( this.config.onAfter ) {
this.config.onAfter();
}
}, 600 );
}
return false;
}
// Render the modal.
render() {
// Set the template.
const html = this.htmlTemplate();
// Create a document fragment.
const docFrag = document.createDocumentFragment();
// Create a <div> on the fly.
this.containerDiv = document.createElement( 'div' );
// Set the HTML of the <div> to the HTML template.
this.containerDiv.innerHTML = html;
// Append the modal HTML to the body.
document.body.appendChild( this.containerDiv );
}
// Modal HTML template.
htmlTemplate() {
return `
<div id="my-modal" class="my-modal" style="background-color:${this.config.backgroundColor}";>
<div class="my-modal-content">
<button id="close">X</button>
<h1>${this.config.modalTitle}!</h1>
<p>${this.config.modalText}</p>
</div>
</div>
`;
}
}
const modalOneTrigger = document.getElementById( 'open-modal-1' );
const modalTwoTrigger = document.getElementById( 'open-modal-2' );
const header = document.getElementsByTagName( 'header' );
new Modal( modalOneTrigger, {
modalTitle: 'Overriding the Title!',
onAfter: function() {
// Let's remove a class to the header!
header[0].classList.remove( 'modal-open' );
},
onBefore: function() {
// Let's remove a class to the header!
header[0].classList.add( 'modal-open' );
}
} );
new Modal( modalTwoTrigger, {
modalTitle: 'This is modal two!',
onAfter: function() {
// Set the background back to the original.
document.querySelector( '.container' ).style.background = '';
},
onBefore: function() {
// Change the background color of the container!
document.querySelector( '.container' ).style.background = '#88C542';
}
} );
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.