├── index.html ├── script.js └── styles.css /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Modal 8 | 9 | 10 | 11 | 12 | 13 | 22 |
23 | 24 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const openModalButtons = document.querySelectorAll('[data-modal-target]') 2 | const closeModalButtons = document.querySelectorAll('[data-close-button]') 3 | const overlay = document.getElementById('overlay') 4 | 5 | openModalButtons.forEach(button => { 6 | button.addEventListener('click', () => { 7 | const modal = document.querySelector(button.dataset.modalTarget) 8 | openModal(modal) 9 | }) 10 | }) 11 | 12 | overlay.addEventListener('click', () => { 13 | const modals = document.querySelectorAll('.modal.active') 14 | modals.forEach(modal => { 15 | closeModal(modal) 16 | }) 17 | }) 18 | 19 | closeModalButtons.forEach(button => { 20 | button.addEventListener('click', () => { 21 | const modal = button.closest('.modal') 22 | closeModal(modal) 23 | }) 24 | }) 25 | 26 | function openModal(modal) { 27 | if (modal == null) return 28 | modal.classList.add('active') 29 | overlay.classList.add('active') 30 | } 31 | 32 | function closeModal(modal) { 33 | if (modal == null) return 34 | modal.classList.remove('active') 35 | overlay.classList.remove('active') 36 | } -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | *, *::after, *::before { 2 | box-sizing: border-box; 3 | } 4 | 5 | .modal { 6 | position: fixed; 7 | top: 50%; 8 | left: 50%; 9 | transform: translate(-50%, -50%) scale(0); 10 | transition: 200ms ease-in-out; 11 | border: 1px solid black; 12 | border-radius: 10px; 13 | z-index: 10; 14 | background-color: white; 15 | width: 500px; 16 | max-width: 80%; 17 | } 18 | 19 | .modal.active { 20 | transform: translate(-50%, -50%) scale(1); 21 | } 22 | 23 | .modal-header { 24 | padding: 10px 15px; 25 | display: flex; 26 | justify-content: space-between; 27 | align-items: center; 28 | border-bottom: 1px solid black; 29 | } 30 | 31 | .modal-header .title { 32 | font-size: 1.25rem; 33 | font-weight: bold; 34 | } 35 | 36 | .modal-header .close-button { 37 | cursor: pointer; 38 | border: none; 39 | outline: none; 40 | background: none; 41 | font-size: 1.25rem; 42 | font-weight: bold; 43 | } 44 | 45 | .modal-body { 46 | padding: 10px 15px; 47 | } 48 | 49 | #overlay { 50 | position: fixed; 51 | opacity: 0; 52 | transition: 200ms ease-in-out; 53 | top: 0; 54 | left: 0; 55 | right: 0; 56 | bottom: 0; 57 | background-color: rgba(0, 0, 0, .5); 58 | pointer-events: none; 59 | } 60 | 61 | #overlay.active { 62 | opacity: 1; 63 | pointer-events: all; 64 | } --------------------------------------------------------------------------------