スキップしてメイン コンテンツに移動

JavaScriptで開いたメニューの外側を暗くして範囲外のクリックでも閉じる方法

サイトに開閉ボタンでメニューを出した際のエフェクトとして外側を暗くすると見易い。そして開閉ボタンだけではなくて開いたメニューの範囲外、または新しく表示された領域外のクリックでも同じように閉じられると使い易い。どう作成するべきか、JavaScriptで実行するプログラムを考えてみる。

開いたメニューの外側を暗くする

プログラムのアイデアとしてhtmlの領域のdiv要素を新たに作成してcssで暗い背景色を付けて開いたメニューと元のコンテンツの間に挿入する方法が挙げられる。

サンプルのソースコード

(開閉ボタン)

※押すとメニューが外側の明暗を変えながら開閉する。

html

<span class="svg-button">
<svg class="hamburger-menu-1" width="142" height="30" viewBox="0 0 142 30"><rect width="28" height="28" x="1" y="1" stroke="#8b008b" stroke-width="1px" fill="none"/><path d="M4 8h22M4 15h22M4 22h22" stroke="#8b008b" stroke-width="3px"/><text x="31" y="15" font-size="16px" dominant-baseline="central">(開閉ボタン)</text></svg>
</span>

<div class="sub-1 hidden">
<ul><li>アイテム①</li><li>アイテム②</li><li>アイテム③</li></ul>
</div>

css

.svg-button {position:relative;z-index:101;}
.svg-button svg {background-color:#ffffff;cursor:pointer;}
.hidden {display:none;}
.sub-1 {width:200px;background-color:#e6e6fa;margin-top:1em;margin-bottom:1em;position:relative;z-index:101;}
.sub-1 ul {list-style:none;padding:1em;}
.dim-overlay {position:fixed;top:0;left:0;width:100%;height:100vh;background-color:rgba(0,0,0,.6);z-index:100;}

JavaScript

var hbm1 = document.getElementsByClassName("hamburger-menu-1")[0];
var sb1 = document.getElementsByClassName("sub-1")[0];
var psb1 = document.getElementsByClassName("post-body")[0];
var bcsd1 = document.createElement("div");
hbm1.onclick = function(){
sb1.classList.toggle("hidden");
if(!sb1.classList.contains("hidden")){
psb1.appendChild(bcsd1).classList.add("dim-overlay");
} else {
psb1.removeChild(bcsd1);
}}

cssの「.dim-overlay」のclassが暗い背景色のデザインで、重なる順番を決めるz-indexの値を通常のコンテンツよりも増やしてメニューの「.sub-1」のclassよりも減らしてそれぞれの間に表示されるようにする。

JavaScriptのcreateElement()メソッドで、htmlのdiv要素を新しく作っておいて開閉ボタンのクリック時点/functionのメニューの開いているか閉じているかの二つの状況/ifに合わせて使う。

メニューの「.sub-1」のclassに非表示の「.hidden」のclassが付いてなくてサイトに表示されていれば新しいdiv要素にclassListプロパティのadd()メソッドで背景を暗くする「.dim-overlay」のclassを付けながら取得した親要素のpsb1へappendChild()メソッドで追加するし、反対にメニューの「.sub-1」のclassに非表示の「.hidden」のclassが付いていてサイトに表示されてなければ追加された背景を暗くするための新しいdiv要素(開閉ボタンが押されると先ずは追加された状態になっている)を取得した親要素のpsb1からremoveChild()メソッドで削除するわけだ。

cssのz-indexで指定できる重なりの順番は兄弟要素間に限られているので、開閉ボタンで表示するメニューと追加する暗い背景色のdiv要素は同一の親要素を持たなくてはならない。

追加するdiv要素の暗い背景色をメニュー以外の画面全体に広げるにはcssのpositionのfixedから縦横を完全に覆うように指定する必要がある。すると上に重ねて表示したいメニューはz-indexの値を上げるだけではなくてさらにpositionなども併せて指定しないと上手く行かなくなるから注意しておきたい。

すなわちcssのpositionのstatic以外の値で、relativeかabsoluteとz-indexがauto以外の場合とfixedかstickyの場合にz-indexの重ね合わせコンテキストが変化するためなんだ。

重ね合わせコンテキストは、ビューポートまたはウェブページに面していると想定されるユーザーに対する仮想的な Z 軸に沿って並べられた HTML 要素の三次元の概念化です。 HTML 要素は、要素の属性に基づいてこの空間を優先度つきの順序で占有します。

重ね合わせコンテキスト via MDN

通常、前よりも後のコンテンツが上に重なるというサイト作成の文脈(コンテキスト)がcssのpositionをstatic以外の値で使うと入れ替わり得る。

なので追加するdiv要素にpositionのfixedを使って表示するメニューとz-indexを的確に機能させるためには両方を同一の親要素に配置すると同時に表示するメニューの重ね合わせコンテキストも何等かの仕方で揃えなくてはならない。

サンプルではpositionのrelativeを開閉ボタンとメニューに記載している。位置取りを変えずにそのままで表示と非表示を切り替えるにはpositionのrelativeを追加するだけで大丈夫だ。

メニューの範囲外のクリックでも閉じる

開いたメニューの外側を暗くする方法とセットで捉えると容易い。というのもメニューの範囲外には背景を暗くするために追加された新しいdiv要素こそ最も高く重なって表示されているためで、それをクリックの対象にすればメニューの範囲外を完全にカバーできる。メニューの範囲外のクリックでも閉じる方法は開いたメニューの外側を暗くする方法に組み込むと一石二鳥のプログラムになる。

サンプルのソースコード

(開閉ボタン)

※押すとメニューが外側の明暗を変えながら開閉する。開いた時点ではメニューの範囲外のクリックでも閉じられる。

html

<span class="svg-button">
<svg class="hamburger-menu-2" width="142" height="30" viewBox="0 0 142 30"><rect width="28" height="28" x="1" y="1" stroke="#8b008b" stroke-width="1px" fill="none"/><path d="M4 8h22M4 15h22M4 22h22" stroke="#8b008b" stroke-width="3px"/><text x="31" y="15" font-size="16px" dominant-baseline="central">(開閉ボタン)</text></svg>
</span>

<div class="sub-2 hidden">
<ul><liアイテム①</li><li>アイテム②</li><li>アイテム③</li></ul>
</div>

css

.svg-button {position:relative;z-index:101}
.svg-button svg {background-color:#ffffff;cursor:pointer;}
.hidden {display:none;}
.sub-2 {width:200px;background-color:#e6e6fa;margin-top:1em;margin-bottom:1em;position:relative;z-index:101;}
.sub-2 ul {list-style:none;padding:1em;}
.dim-overlay {position:fixed;top:0;left:0;width:100%;height:100vh;background-color:rgba(0,0,0,.6);z-index:100;}

JavaScript

var hbm2 = document.getElementsByClassName("hamburger-menu-2")[0];
var sb2 = document.getElementsByClassName("sub-2")[0];
var psb2 = document.getElementsByClassName("post-body")[0];
var bcsd2 = document.createElement("div");
hbm2.onclick = function(){
sb2.classList.toggle("hidden");
if(!sb2.classList.contains("hidden")){
psb2.appendChild(bcsd2).classList.add("dim-overlay");
} else {
psb2.removeChild(bcsd2);
}};
bcsd2.onclick = function(){
sb2.classList.add("hidden");
psb2.removeChild(bcsd2);
}

メニューの外側を暗くする開閉ボタンのソースコードの新たに作って挿入したdiv要素をメニューの範囲外としても扱ってサイトに出て来たらクリックを判定して閉じるという太字の部分のJavaScriptを追加する。

単独でメニューの範囲外のクリックだけ行う場合はJavaScriptで新たに作って挿入するdiv要素にcssで背景色を付けずに無色のままで使う。

コメント

些細な日常の人気の投稿

PlayストアでAndroidアプリのダウンロードが非常に遅い場合の打開策

イメージ

ジャパネットたかたの丸尾詩織の商品説明に気持ちが入っていて素晴らしい理由

イメージ