Popup Modal

Requer fade.js e icons.js

Para ativar uma janela popup, adicione o atributo data-popup-modal ao botão com o mesmo valor id do popup. Com isso o botão estará configurado para abrir a janela modal de popup correspondente.

<button data-popup-modal="exemple_modal_popup" class="btn">Demonstração</button>
<div id="exemple_modal_popup" class="popup" role="dialog">
    <div class="modal">
        <div class="modal_header">
            <h3>Cabeçalho popup modal</h3>
        </div>
        <div class="modal_main">
            <p>Conteúdo</p>
        </div>
        <div class="modal_footer">
            <h6>Rodapé</h6>
        </div>
    </div>
</div>

Cabeçalho: .modal_header e Rodapé: modal_footer são opcionais.


Popup modal com barra de rolagem

Adicione a classe scroll junto ao elemento popup.

<button data-popup-modal="modal_popup_scrollbar" class="btn">Demonstração</button>
<div id="modal_popup_scrollbar" class="popup scroll" role="dialog">
    ...
</div>

Popup modal centralizado verticalmente

Esse janela de modal popup tem um elemento a mais que os outros.

<button data-popup-modal="modal_popup_centered" class="btn">Demonstração</button>
<div id="modal_popup_centered" class="popup" role="dialog">
    <div class="axis_xy">
        <div class="modal">
            ...
        </div>
    </div>
</div>

Popup modal não fecha ao clicar fora dele.

Adicione o atributo data-popup-overlay="false" no elemento .popup.
Isso irá bloquear o fechamento da janela de dialogo quando o usuário clicar fora do mesmo ou precionar a tecla Esc.

<button data-popup-modal="not_overlay_or_esc" class="btn">Demonstração</button>
<div id="not_overlay_or_esc" class="popup" data-popup-overlay="false" role="dialog">
    <div class="modal">
        ...
    </div>
</div>

Popup modal no canto:


Opções de tamanhos


Popup Modal Fullscreen

<button data-popup-modal="popup_modal_fullscreen" class="btn">Demonstração</button>
<div id="popup_modal_fullscreen" class="popup fullscreen" role="dialog">
    <div class="modal">
        ...
    </div>
</div>

.popup {
    --popup__background: rgba(0, 0, 0, 0.85);
    --modal__color: #616161;
    --modal__background: #F2F2F2;
    --modal__border: 1px solid #FFFFFF;
    --modal__border-width: 1px;
    --modal__border-style: solid;
    --modal__border-color: #FFFFFF;
    --modal__box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    --modal__border-radius: 4px;
    --modalCorners__border-radius: 2px;
    --modalHeader__background: #E7E7E7;
    --modalFooter__background: #E7E7E7;

    /* declaracoes .popup */
    display: none;
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    z-index: 8891;
    background-color: var(--popup__background);
}
.popup .modal {
    position: relative;
    width: 600px;
    max-width: 100%;
    margin: 9px 9px;
    padding: 0;
    color: var(--modal__color);
    background-color: var(--modal__background);
    border: var(--modal__border);
    box-shadow: var(--modal__box-shadow);
    border-radius: var(--modal__border-radius);
    overflow: hidden;
    animation: dialog_show 1s both;
    z-index: 8893;
}

.popup.xsm .modal {
    width: 300px;
}
.popup.sm .modal {
    width: 400px;
}
.popup.lg .modal {
    width: 800px;
}
.popup.xlg .modal {
    width: 1000px;
}

.popup.top_left .modal, .popup.top_right .modal, .popup.bottom_left .modal, .popup.bottom_right .modal {
    width: 300px !important;
    border-radius: var(--modalCorners__border-radius);
}
.popup.bottom_left .modal, .popup.bottom_right .modal {
    position: absolute;
    bottom: 0.5vh;
}
.popup.top_left .modal {
    margin: 0.5vh auto auto 0.5vh;
}
.popup.top_right .modal {
    margin: 0.5vh 0.5vh auto auto;
}
.popup.bottom_left .modal {
    left: 0.5vh;
    margin: auto auto 0.5vh 0.5vh;
}
.popup.bottom_right .modal {
    right: 0.5vh;
    margin: auto 0.5vh auto 0.5vh;
}

.popup.scroll .modal {
    margin: 2.5vh auto;
    max-height: 95vh;
    overflow-y: auto;
}

.popup.fullscreen .modal {
    display: flex;
    flex-direction: column;
    max-width: none;
    width: 100%;
    max-height: none;
    height: 100%;
    margin: 0 0;
    border-radius: 0;
}
.popup.fullscreen .modal .modal_main {
    flex: 1 1 auto;
}

.popup .axis_xy {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 8893;
}
.popup .axis_xy .modal {
    margin: auto auto;
    height: auto;
    max-height: 80vh;
    overflow-y: auto;
}

.popup .modal.show {
    animation: none;
}
.popup .modal.shake {
    animation: dialog_shake 1s both;
}

.popup .modal p:first-child {
    margin-top: 0;
}
.popup .modal p:last-child {
    margin-bottom: 0;
}

.popup .modal_main {
    position: relative;
    padding: 10px 15px;
}
.modal_header, .modal_footer {
    position: relative;
    padding: 7px 15px;
    background-color: var(--modalHeader__background);
}
.modal_header {
    border-bottom: var(--modal__border);
}
.modal_footer {
    border-top: var(--modal__border);
}
.modal_header h2, .modal_header h3, .modal_header h4, .modal_header h5, .modal_header h6,
.modal_footer h2, .modal_footer h3, .modal_footer h4, .modal_footer h5, .modal_footer h6 {
    margin: 0 0 0 0 !important;
    padding: 0 0 0 0 !important;
    font-weight: 400;
}

[icon=x].popup_close {
    position: absolute;
    top: 11px;
    right: 11px;
    width: 20px;
    height: 18px;
    cursor: pointer;
    overflow: hidden;
    color: #111;
    filter: drop-shadow(0 1px rgba(255, 255, 255, 0.30));
    line-height: 0;
    border: none;
    background-color: transparent;
    padding: 0 0;
    margin: 0 0;
    z-index: 8894;
}
[icon=x].popup_close .ico.x {
    position: absolute;
    top: -5px; left: -5px;
    width: 100%;
    min-width: 30px;
}

.popup_over {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    z-index: 1;
}
@media(min-width: 550px) {
    .popup .modal {
        margin: 2.5vh auto;
    }
}

@keyframes dialog_show {
    0% {
        opacity: 0;
        transform: translateY(-500px);
    }
    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes dialog_shake {
    0%, 100% {
        transform: translateX(0);
    }
    10%, 30%, 50%, 70%, 90% {
        transform: translateX(-10px);
    }
    20%, 40%, 60%, 80% {
        transform: translateX(10px);
    }
}
let popup = {
    openDialog: document.querySelectorAll("[data-popup-modal]"),
    popupDialog: document.querySelectorAll(".popup"),
    modalDialog: document.querySelectorAll(".modal"),
    modal: function() {
        this.openDialog.forEach( element => {
            element.addEventListener('click', function() {
                var dialog = document.getElementById(this.dataset.popupModal);
                dialog.style.display = "block";

                document.body.style.overflowY = "hidden";
            });
        });

        this.popupDialog.forEach( element => {
            var overlay = document.createElement("div");
            overlay.classList.add("popup_over");
            element.append(overlay);
            if( element.hasAttribute("data-popup-overlay") ) {
                var dialog = document.querySelector("#"+element.id+" .modal");
                overlay.addEventListener('click', function() {
                    dialog.classList.add("shake");
                    window.setTimeout(function () {
                        dialog.classList.remove("shake");
                    }, 450);
                    dialog.classList.add("show");
                });

                document.addEventListener('keydown', event => {
                    if(event.key == "Escape") {
                        dialog.classList.add("shake");
                        window.setTimeout(function () {
                            dialog.classList.remove("shake");
                        }, 450);
                        dialog.classList.add("show");
                    }
                });
            }
            else {
                overlay.addEventListener('click', function() {
                    fade.out.get(element, 400);
                    window.setTimeout(function () {
                        element.style.removeProperty("display");
                        element.style.removeProperty("opacity");
                        document.body.style.removeProperty("overflow-y");
                    }, 450);
                });

                document.addEventListener('keydown', event => {
                    if(event.key == "Escape") {
                        fade.out.get(element, 400);
                        window.setTimeout(function () {
                            element.style.removeProperty("display");
                            element.style.removeProperty("opacity");
                        }, 450);
                    }
                });
            }
        });

        this.modalDialog.forEach( element => {
            var close = document.createElement("button");
            close.classList.add("popup_close");
            close.setAttribute("icon", "x");
            close.setAttribute("aria-label", "Click para fechar");
            element.prepend(close);
            var closeElement = element.parentElement;
            if( element.parentElement.classList.contains("axis_xy") ) {
                closeElement = element.parentElement.parentElement;
            }
            close.addEventListener('click', function() {
                fade.out.get(closeElement, 400);
                window.setTimeout(function () {
                    closeElement.style.removeProperty("display");
                    closeElement.style.removeProperty("opacity");
                    document.body.style.removeProperty("overflow-y")
                }, 450);
                element.classList.remove("show");
            });
        });

        if( document.querySelectorAll("[data-close-element]") ) {
            var btnDiscard = document.querySelectorAll("[data-close-element]");
            btnDiscard.forEach( element => {
                element.addEventListener('click', function() {
                    var closeElement = document.getElementById(this.dataset.closeElement);
                    fade.out.get(closeElement, 400);
                    window.setTimeout(function () {
                        closeElement.style.removeProperty("display");
                        closeElement.style.removeProperty("opacity");
                        document.body.style.removeProperty("overflow-y");
                    }, 450);
                    var dialog = document.querySelector("#"+this.dataset.closeElement+" .modal");
                    dialog.classList.remove("show");
                });
            });
        }
    }
}
.modal();