ベーシックモーダル
×ボタン・背景クリック・Escキーで閉じます。閉じるとフォーカスは開いたボタンへ戻ります。
<div class="bnto-mdl" data-bnto-mdl> <button type="button" class="op">モーダルを開く</button> <div class="bx" role="dialog" aria-modal="true" aria-label="お知らせ"> <div class="ov" data-close></div> <div class="pn"> <button type="button" class="x" data-close aria-label="閉じる">✕</button> <h3 class="tt">モーダルタイトル</h3> <p class="tx">ここに本文を書きます。</p> </div> </div> </div>
.bnto-mdl { --c1: hsl(9 84% 58%); /* アクセント色 */ --dur: .3s; /* 表示アニメの速さ */ } .bnto-mdl .op { padding: 11px 20px; border: none; border-radius: 12px; background: var(--c1); color: #fff; font: inherit; font-weight: 800; cursor: pointer; } /* デモの都合でカード内に absolute 表示。 ページ全体に被せるなら position: fixed に変更 */ .bnto-mdl .bx { position: absolute; inset: 0; z-index: 30; display: none; align-items: center; justify-content: center; } .bnto-mdl .bx.is-open { display: flex; } .bnto-mdl .ov { position: absolute; inset: 0; background: rgba(32,26,20,.45); animation: bnto-mdl-f var(--dur) ease; } .bnto-mdl .pn { position: relative; width: min(88%, 250px); background: #fff; border-radius: 16px; padding: 18px; box-shadow: 0 18px 44px rgba(0,0,0,.25); animation: bnto-mdl-p var(--dur) ease; } .bnto-mdl .tt { margin: 0 26px 8px 0; font-size: 14px; color: var(--c1); } .bnto-mdl .tx { margin: 0; font-size: 12.5px; line-height: 1.75; } .bnto-mdl .x { position: absolute; top: 10px; right: 10px; width: 26px; height: 26px; border: none; border-radius: 8px; background: #EAF2F8; cursor: pointer; } @keyframes bnto-mdl-f { from { opacity: 0; } } @keyframes bnto-mdl-p { from { opacity: 0; transform: translateY(12px) scale(.96); } }
// data-bnto-mdl を自動検出して初期化(複数設置OK・二重実行OK) (function () { document.querySelectorAll('[data-bnto-mdl]').forEach(function (root) { if (root.dataset.bntoInit) return; root.dataset.bntoInit = '1'; var opener = root.querySelector('.op'); var box = root.querySelector('.bx'); function onKey(e) { if (e.key === 'Escape') close(); } function close() { box.classList.remove('is-open'); document.body.style.overflow = ''; // 背面スクロール解除 document.removeEventListener('keydown', onKey); opener.focus(); // フォーカスを開くボタンへ返す } opener.addEventListener('click', function () { box.classList.add('is-open'); document.body.style.overflow = 'hidden'; // 背面スクロール固定 document.addEventListener('keydown', onKey); box.querySelector('.x').focus(); }); box.addEventListener('click', function (e) { if (e.target.closest('[data-close]')) close(); }); }); })();
使い方のコツ
デモはカード内に表示していますが、実際のページ全体に被せるときは .bx を position:fixed に変えるだけです。閉じるボタン・背景・Escの3経路で閉じられるのがモーダルUXの基本形です。