<div class="bnto-dd" data-bnto-dd> <button type="button" class="bnto-dd-btn"> メニュー <svg class="ar" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg> </button> <div class="bnto-dd-menu"> <a href="#">項目1</a> <a href="#">項目2</a> <a href="#">項目3</a> </div> </div>
.bnto-dd { --c1: hsl(202 73% 50%); /* アクセント色 */ --dur: .25s; /* 開閉スピード */ position: relative; display: inline-block; } .bnto-dd-btn { display: inline-flex; align-items: center; gap: 8px; padding: 11px 18px; background: var(--c1); color: #fff; border: none; border-radius: 12px; font: inherit; font-weight: 800; cursor: pointer; } .bnto-dd-btn .ar { transition: transform var(--dur); } .bnto-dd.is-open .bnto-dd-btn .ar { transform: rotate(180deg); } /* メニュー本体(ボタンの下に浮かせる) */ .bnto-dd-menu { position: absolute; top: calc(100% + 8px); left: 0; min-width: 190px; z-index: 5; background: #fff; border: 2px solid #DFE9F1; border-radius: 12px; padding: 6px; box-shadow: 0 12px 28px rgba(0,0,0,.12); opacity: 0; visibility: hidden; transform: translateY(-6px); transition: opacity var(--dur), transform var(--dur), visibility var(--dur); } .bnto-dd.is-open .bnto-dd-menu { opacity: 1; visibility: visible; transform: none; } .bnto-dd-menu a { display: block; padding: 9px 12px; border-radius: 8px; color: #1D2A36; text-decoration: none; font-weight: 700; } .bnto-dd-menu a:hover { background: #EAF2F8; color: var(--c1); }
// data-bnto-dd を自動検出して初期化(複数設置OK・二重実行OK) (function () { document.querySelectorAll('[data-bnto-dd]').forEach(function (dd) { if (dd.dataset.bntoInit) return; dd.dataset.bntoInit = '1'; var btn = dd.querySelector('.bnto-dd-btn'); btn.setAttribute('aria-haspopup', 'true'); btn.setAttribute('aria-expanded', 'false'); btn.addEventListener('click', function () { var open = dd.classList.toggle('is-open'); btn.setAttribute('aria-expanded', open); }); }); // 外側クリック / Esc で閉じる(documentへの登録は1回だけ) if (document.documentElement.dataset.bntoDdDoc) return; document.documentElement.dataset.bntoDdDoc = '1'; function closeAll(except) { document.querySelectorAll('[data-bnto-dd].is-open').forEach(function (dd) { if (dd === except) return; dd.classList.remove('is-open'); dd.querySelector('.bnto-dd-btn').setAttribute('aria-expanded', 'false'); }); } document.addEventListener('click', function (e) { closeAll(e.target.closest('[data-bnto-dd]')); }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeAll(null); }); })();
使い方のコツ
外側クリックとEscキーで閉じる処理まで込みの基本形です。メニューを右揃えにしたいときは .bnto-dd-menu の left: 0 を right: 0 に変えるだけです。