画面の上または下からスライドして表示される、横並びドロワーメニューの作り方を紹介します。メニュー項目を横一列に配置し、画面の端から滑らかに出し入れできる仕組みです。
今回のデモでは、「上から開く」と「下から開く」の2つのボタンを用意しています。上から開く場合は画面上端から下方向へ、下から開く場合は画面下端から上方向へメニューがスライドします。どちらも画面の横幅いっぱいに表示されます。
メニューには「ホーム」「サービス」「お知らせ」「お問い合わせ」の4項目を横並びで配置しています。画面幅が狭く、すべての項目が収まらない場合は、メニュー部分を横スクロールして確認できます。
メニューを開くと背景が暗くなり、右上の「×」ボタン、背景部分のクリック、Escキーで閉じられます。上下どちらの方向から開く場合も、閉じると開いた方向へ戻ります。
デモ
メニューを開くと、画面の上または下から横並びのメニューが表示されます。
「上から開く」「下から開く」のボタンをクリックすると、画面の上端または下端から横並びのドロワーメニューがスライドして表示されます。メニュー項目は横一列に配置され、画面幅が狭い場合は横スクロールで確認できます。右上の「×」ボタン、暗くなった背景のクリック、Escキーで閉じられます。
コードをコピーして使おう!
<!DOCTYPE html>
<html lang="ja">
<head>
<!-- 文字コードの設定 -->
<meta charset="UTF-8">
<!-- スマートフォンなどの画面幅に対応 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- ページタイトル -->
<title>画面の上下から開く横並びドロワーメニュー</title>
<!-- ドロワーメニューのCSSを読み込む -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- ドロワーメニューを開くボタン -->
<button
class="top-bottom-horizontal-drawer_trigger"
type="button"
aria-controls="top-bottom-horizontal-drawer-panel"
aria-expanded="false"
>
メニューを開く
</button>
<!-- メニュー表示中に背景を暗くするオーバーレイ -->
<div class="top-bottom-horizontal-drawer_overlay" aria-hidden="true"></div>
<!-- ドロワーメニュー本体。初期設定では画面下から開く -->
<div
class="top-bottom-horizontal-drawer_panel"
id="top-bottom-horizontal-drawer-panel"
aria-hidden="true"
inert
>
<!-- メニュー上部 -->
<div class="top-bottom-horizontal-drawer_header">
<div class="top-bottom-horizontal-drawer_heading">
メニュー
</div>
<!-- メニューを閉じるボタン -->
<button
class="top-bottom-horizontal-drawer_close"
type="button"
aria-label="メニューを閉じる"
>
×
</button>
</div>
<!-- 横並びのメニューリンク。hrefは実際のリンク先に変更する -->
<nav class="top-bottom-horizontal-drawer_nav" aria-label="ドロワーメニュー">
<a class="top-bottom-horizontal-drawer_link" href="#">
ホーム
</a>
<a class="top-bottom-horizontal-drawer_link" href="#">
サービス
</a>
<a class="top-bottom-horizontal-drawer_link" href="#">
お知らせ
</a>
<a class="top-bottom-horizontal-drawer_link" href="#">
お問い合わせ
</a>
</nav>
</div>
<!-- ドロワーメニューの開閉処理を読み込む -->
<script src="script.js"></script>
</body>
</html>
コードをコピーする場合 使用するコードのタブを選び、「このタブをコピー」をクリックすると、現在表示中のコードをコピーできます。 サンプル一式を取得する場合 HTML・CSSなどすべてのファイルが必要な場合は、「サンプル一式をダウンロード」をクリックしてください。
Q ダウンロードしたけど、これをネット上で動かすにはどうするの?
Googleアカウントがあれば、InfinityFreeで無料サーバーを作成して、ダウンロードしたサンプルをネット上で動かせます。
InfinityFreeを初めて利用する場合は①から、すでにサーバーを作成している場合は②へ進んでください。
ファイル構成と設置方法
このサンプルは、HTML・CSS・JavaScriptの3つのファイルで構成されています。 HTMLにはメニューを開くボタン、背景オーバーレイ、横並びのリンクを持つドロワーメニューを配置しています。 CSSでは画面下から開くスライド動作を基本に、画面上から開くための設定もコメントアウトで用意しています。 JavaScriptではメニューの開閉と、閉じるボタン・背景クリック・Escキーによる操作を制御しています。
sample/
├── index.html
├── style.css
└── script.js
各ファイルの役割
index.htmlには、「メニューを開く」ボタン、背景オーバーレイ、メニューのタイトル、閉じるボタン、4つの横並びリンクを記述しています。
style.cssでは、ドロワーの表示位置・高さ・スライド方向・開閉アニメーションと、横並びリンクの配置を設定しています。
script.jsでは、開閉状態を切り替えるopenMenu()とcloseMenu()を使い、ボタン操作やEscキーに対応しています。
設置方法・使い方
「サンプル一式をダウンロード」をクリックしてZIPファイルを保存し、展開してください。
sampleフォルダ内のindex.html・style.css・script.jsを同じ階層に配置します。
index.htmlをブラウザで開くと、「メニューを開く」ボタンが表示されます。
ボタンをクリックすると画面下から横並びのドロワーメニューがスライドして表示され、背景が暗くなります。
メニュー右上の「×」ボタン、暗くなった背景のクリック、Escキーで閉じられます。
画面上から開く形に変更したい場合は、後述するstyle.cssの方向設定を切り替えてください。
画面下から開くドロワーの仕組み
初期設定では、style.cssの次の部分でドロワーを画面下端に配置しています。
閉じているときは、メニュー自身の高さ分だけ下へ移動させ、画面外に隠しています。
/* =========================================
下から開くドロワーメニュー(初期設定)
========================================= */
.top-bottom-horizontal-drawer_panel {
left: 0; /* 画面の左端に合わせる */
bottom: 0; /* 画面の下端に合わせる */
transform: translateY(100%); /* メニュー自身の高さ分だけ下へ隠す */
}
bottom: 0;でメニューを画面下端に配置し、left: 0;で左端に合わせています。
translateY(100%)は、メニュー自身の高さの100%分だけ下へ移動する指定です。
共通設定のwidth: 100%;によって横幅いっぱいに表示され、
max-height: 70dvh;で高さの上限を表示領域の70%にしています。
高さの上限を小さくしたい場合は50dvh、大きくしたい場合は80dvhなどに変更できます。
max-height: 70vh;は、dvhに対応していないブラウザ向けの指定です。
画面上から開く方法
画面上から開く場合は、style.cssにある「下から開くドロワーメニュー(初期設定)」のCSSブロックを削除し、
続く「上から開く場合の設定」のコメントアウトを解除してください。
/* =========================================
上から開く場合の設定(コメントアウト)
上から開く場合は下方向の設定を削除し、
次のCSSのコメントアウトを解除する
========================================= */
/*
.top-bottom-horizontal-drawer_panel {
top: 0;
left: 0;
transform: translateY(-100%);
}
*/
有効にするには、先頭の/*と末尾の*/を削除します。
top: 0;でメニューを画面上端に配置し、translateY(-100%)でメニュー自身の高さ分だけ上へ隠します。
開くときは画面上から下方向へスライドし、閉じるときは上方向へ戻ります。
translateY(100%)とtranslateY(-100%)の違いは移動方向です。
正の値では下方向、負の値では上方向へ移動します。
どちらもメニュー自身の高さを基準とするため、メニューの高さを変更しても画面外へ移動できます。
下方向と上方向の設定は、どちらか一方だけを有効にしてください。
開閉アニメーションと表示状態
メニューを開くと、JavaScriptによってis-activeクラスが追加されます。
このクラスが付くと、下方向または上方向に隠れていたメニューが画面内へ移動します。
/* =========================================
メニューを開いた状態
========================================= */
.top-bottom-horizontal-drawer_panel.is-active {
transform: translateY(0); /* 画面内の表示位置へスライドする */
visibility: visible; /* メニューを表示する */
pointer-events: auto; /* メニュー内の操作を有効にする */
box-shadow: 0 0 30px rgba(15, 23, 42, 0.18); /* メニューの周囲に影を表示する */
}
translateY(0)は縦方向の移動量を0に戻す指定です。
下から開く場合も上から開く場合も、共通のCSSで画面内へスライドさせています。
アニメーションの速度は、.top-bottom-horizontal-drawer_panelの共通設定にある
transition: transform 0.3s ease, visibility 0.3s ease;で調整できます。
0.3sを0.5sにするとゆっくり、0.2sにすると速くなります。
box-shadowの30pxは影のぼかし範囲、0.18は影の不透明度です。
影を目立たせたい場合は不透明度を大きくし、薄くしたい場合は小さくしてください。
メニュー項目を横並びにする仕組み
横並びのメニューは、style.cssの.top-bottom-horizontal-drawer_navで設定しています。
display: flex;とflex-direction: row;によって、4つのリンクを横一列に配置しています。
/* =========================================
横並びメニュー
========================================= */
.top-bottom-horizontal-drawer_nav {
display: flex; /* メニュー項目を横並びにする */
flex-direction: row; /* 横方向に並べる */
gap: 12px; /* 項目間の余白 */
overflow-x: auto; /* 横幅に収まらない場合は横スクロールを可能にする */
padding-bottom: 4px; /* スクロールバーとの間隔 */
}
gap: 12px;はリンク同士の間隔です。
20pxに変更すると間隔が広くなり、8pxに変更すると狭くなります。
overflow-x: auto;を指定しているため、リンクが画面幅に収まらない場合はメニュー部分を横スクロールできます。
画面が狭くてもリンクを無理に折り返さず、横並びを維持する構成です。
横並びリンクの幅と高さ
各リンクには.top-bottom-horizontal-drawer_linkを設定しています。
文字を中央に配置し、リンク全体をクリックできる領域にしています。
/* 各メニューリンク */
.top-bottom-horizontal-drawer_link {
display: flex; /* 文字を中央に配置する */
align-items: center; /* 縦方向の中央に揃える */
justify-content: center; /* 横方向の中央に揃える */
flex: 1 0 120px; /* 均等に広げ、基本横幅を120pxにする */
min-height: 52px; /* リンクの最小の高さ */
padding: 14px 16px; /* 上下14px・左右16pxの内側余白 */
border-radius: 8px; /* リンクの角丸 */
background: #f1f5f9; /* リンクの背景色 */
color: #111827; /* リンクの文字色 */
font-size: 16px; /* 文字サイズ */
font-weight: 700; /* 文字の太さ */
text-align: center; /* 文字を中央揃えにする */
text-decoration: none; /* 下線を表示しない */
white-space: nowrap; /* リンク内の文字を折り返さない */
box-sizing: border-box; /* 余白を横幅と高さに含める */
}
flex: 1 0 120px;は、各リンクの基本横幅を120pxとし、余裕がある場合は均等に広げ、狭い場合でも縮めない設定です。
基本横幅を広げたい場合は160px、狭くしたい場合は100pxなどに変更できます。
min-height: 52px;はリンクの最小の高さです。
60pxにすると縦に大きく、44pxにするとコンパクトになります。
white-space: nowrap;によってリンク内の文字を折り返さないため、長い項目名でも横並びを維持できます。
リンクの文字やリンク先はindex.htmlで変更します。
「ホーム」「サービス」「お知らせ」「お問い合わせ」の文字を変更でき、各a要素のhref="#"には実際の移動先URLを指定してください。
項目を増やしたい場合は、同じクラスを付けたa要素をnav内に追加します。
JavaScriptでメニューを開く処理
script.jsでは、「メニューを開く」ボタンがクリックされるとopenMenu()を実行します。
メニュー本体と背景オーバーレイにis-activeクラスを追加し、開いた状態へ切り替えています。
/* =========================================
メニューを開く
========================================= */
function openMenu() {
// ドロワー内の操作を有効にする
drawer.inert = false;
// ドロワーと背景オーバーレイを表示する
drawer.classList.add("is-active");
overlay.classList.add("is-active");
// アクセシビリティ用の開閉状態を更新する
drawer.setAttribute("aria-hidden", "false");
openButton.setAttribute("aria-expanded", "true");
// × 閉じるボタンへフォーカスを移動する
closeButton.focus();
}
drawer.classList.add("is-active")によってドロワーがスライドして表示され、
overlay.classList.add("is-active")で背景が暗くなります。
drawer.inert = false;はメニュー内の操作を有効にする処理です。
aria-hiddenとaria-expandedも開いた状態に更新し、
最後にcloseButton.focus()で「×」ボタンへフォーカスを移動します。
閉じるボタン・背景クリック・Escキーによる操作
メニューを閉じるときはcloseMenu()を実行します。
メニューと背景オーバーレイからis-activeクラスを削除すると、CSSで設定した画面外の位置へ戻ります。
/* =========================================
メニューを閉じる
========================================= */
function closeMenu() {
// メニューを開いたボタンへフォーカスを戻す
openButton.focus();
// ドロワーと背景オーバーレイを非表示にする
drawer.classList.remove("is-active");
overlay.classList.remove("is-active");
// アクセシビリティ用の開閉状態を更新する
drawer.setAttribute("aria-hidden", "true");
openButton.setAttribute("aria-expanded", "false");
// 非表示中のドロワー内の操作を無効にする
drawer.inert = true;
}
openButton.focus()でメニューを開いたボタンへフォーカスを戻し、
aria-hidden="true"とinertで閉じたメニューを操作対象から外します。
「×」ボタンと背景オーバーレイにはclickイベントを登録し、どちらもcloseMenu()を呼び出しています。
Escキーについては、メニューが開いているときだけ閉じる処理を実行します。
/* =========================================
Escキーで閉じる
========================================= */
document.addEventListener("keydown", function(event) {
// メニューが開いているときだけEscキーで閉じる
if (
event.key === "Escape" &&
drawer.classList.contains("is-active")
) {
closeMenu();
}
});
event.key === "Escape"でEscキーが押されたことを確認し、
drawer.classList.contains("is-active")でメニューが開いているかを判定しています。
この2つの条件を満たした場合だけcloseMenu()を実行します。
背景の暗さは、style.cssの.top-bottom-horizontal-drawer_overlayにある
background: rgba(15, 23, 42, 0.45);で調整できます。
最後の0.45を大きくすると背景が暗く、小さくすると薄くなります。
スマートフォンでの横並び表示
style.cssでは、画面幅640px以下で開くボタンとドロワー内部の余白、メニューリンクの文字サイズなどを調整しています。
横並びの配置は維持し、リンクが収まらない場合は横スクロールできるようにしています。
/* =========================================
スマートフォン対応
========================================= */
@media (max-width: 640px) {
/* スマートフォンで開くボタンを調整する */
.top-bottom-horizontal-drawer_trigger {
min-height: 48px; /* ボタンの最小の高さ */
padding: 10px 12px; /* 上下10px・左右12pxの内側余白 */
font-size: 14px; /* 文字サイズ */
}
/* スマートフォンでメニュー内の余白を調整する */
.top-bottom-horizontal-drawer_panel {
padding: 24px 18px; /* 上下24px・左右18pxの内側余白 */
}
/* メニュー上部とリンクの間隔を小さくする */
.top-bottom-horizontal-drawer_header {
margin-bottom: 20px; /* メニュー項目との間隔 */
}
/* メニュータイトルの文字サイズを調整する */
.top-bottom-horizontal-drawer_heading {
font-size: 22px; /* 文字サイズ */
}
/* スマートフォンでリンクの大きさを調整する */
.top-bottom-horizontal-drawer_link {
flex-basis: 120px; /* リンクの基本横幅 */
min-height: 48px; /* リンクの最小の高さ */
padding: 12px 14px; /* 上下12px・左右14pxの内側余白 */
font-size: 14px; /* 文字サイズ */
}
}
PCでは開くボタンの最小の高さを52px、文字サイズを16pxにしていますが、
画面幅640px以下では高さ48px、文字サイズ14pxに変更しています。
ドロワー内部の余白も上下32px・左右24pxから、上下24px・左右18pxへ縮小します。
メニューリンクの基本横幅はスマートフォンでも120pxを維持し、文字サイズを14pxにしています。
overflow-x: auto;によって、リンクが横幅に収まらない場合も横一列のままスクロールできます。
画面幅を切り替える基準はmax-width: 640pxです。
例えば768pxに変更すると、より広い画面幅からスマートフォン向けのスタイルが適用されます。
コメント