.modal-overlay
.modal
.modal-dialog
.modal-content
.modal-header
.modal-title
.modal-close
.modal-body
.modal-footer
.modal-center
.modal-bottom-sheet
.modal-full-height
.modal-full-screen
.modal-half-screen
.reverse
.animate
.fromtop
.fromleft
.fromright
.frombottom
A modal window from a CSS point of view is very simple, what is left is to connect the behavior to javascript button clicks to show and hide. Also, no real stying is added in framework, allowing for full custom styling.
The dialog HTML is as follows, in its basic shape (javascript is needed to make it interactive).
<div class="modal-overlay">
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="f6 modal-title">Title of dialog</h6>
<button type="button" class="modal-close"></button>
</div>
<div class="modal-body">
Content of body
</div>
<div class="modal-footer">
footer content
</div>
</div>
</div>
</div>
</div>
To use any of the following styles of the modal, wrap the modal window or apply the classname to the root node.
<div class="modal-overlay modal-center">
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="f6 modal-title">Title of dialog</h6>
<button type="button" class="modal-close"></button>
</div>
<div class="modal-body">
Content of body
</div>
<div class="modal-footer">
footer content
</div>
</div>
</div>
</div>
</div>
or wrap it
<div class="modal-center">
<div class="modal-overlay">
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="f6 modal-title dr-title">Title of dialog</h6>
<button type="button" class="modal-close"></button>
</div>
<div class="modal-body">
Content of body
</div>
<div class="modal-footer">
footer content
</div>
</div>
</div>
</div>
</div>
</div>
Animation through css is the best way to animate. Following are basic class names you can add to the
wrapper, or root node. When binding behavior, apply the rule to show or hide to the .modal-overlay
element, to get results. The animation rules apply
to all
modals, but below are the best suitable combination for each animation.
Following is the list of LESS variables that affect the dialog style.
@modal-bg
fade(@black, 60)
@modal-zindex
@modal-zindex - 10
1040
@modal-margin
md
minimum width, the margins are set to auto
@space
@modal-padding
@halfspace
@modal-md-width
md
minimum width.
700px
@modal-scrollbar-width
5px
@trans-func
cubic-bezier(.4,0,.2,1);
You can pass any wrapper style to redefine the look and feel, here are some examples.
// define a close icon for the modal-close
.modal-close {
.getIcon(@icon-close);
}
// add style for footer
.modal-footer {
background-color: @grey-light;
}
// yellow info dialog
.modal-info {
.modal-dialog {
max-width: 30vw;
width: 300px;
}
.modal-content {
background-color: @yellow-light;
}
.modal-footer {
background-color: @yellow;
}
}
If you designed interfaces for mobile devices, you probably ran into this problem, where the browser
address bar appears, or disappears according to user swiping up, or down. This affects the available
height of the content without changing vh
value. To fix that, with a little of javascript,
here is what you can do.
function setValue() {
// dynamically set the --vh css variable
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}
// set on load of page, and also watch window resize
setValue();
window.addEventListener('resize', setValue);
In your css (less):
.modal-content {
max-height: calc((var(--vh, 1vh) * 100));
}
.modal-half-screen .modal-content {
min-height: calc((var(--vh, 1vh) * 100));
max-height: calc((var(--vh, 1vh) * 100));
}
Following is the least amount of javascript needed to get modals to work.
class Modal {
config = {
closeSelector: '.modal-close',
modalContentSelector: '.modal-content',
triggerAttr: 'data-trigger'
};
constructor(element) {
this.modalElement = element;
this.trigger = element.getAttribute(this.config.triggerAttr);
this.modalElement.addEventListener('click', event => {
const target = event.target;
if (!target.closest(this.config.modalContentSelector)) {
this.hide();
}
// if target is close, hide
if (target.matches(this.config.closeSelector)) {
this.hide();
}
});
window.document.addEventListener('click', event => {
const target = event.target;
if (this.trigger) {
if (target.matches(this.trigger) || target.closest(this.trigger)) {
// itself or its parent
this.show();
}
}
});
}
show = () => {
this.modalElement.style.display = 'block';
};
hide = () => {
this.modalElement.style.display = 'none';
};
}
function setVh() {
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}
window.addEventListener('DOMContentLoaded', (event) => {
// set --vh
setVh();
window.addEventListener('resize', setVh);
// find dialogs and attach behaviors
const modals = document.querySelectorAll('.modal-overlay');
modals.forEach(n => {
new Modal(n);
});
});