ふと気になって調べること数十回。自分の中で区切りをつけたいので記事にまとめます!
あと、諳んじる必要は全く無いと思っています!
環境
BrowserがあればOKです。
一応、リポジトリにNode プロジェクトとしても作ってあります。npm run start
で動きます。
実装
Modal構成要素
- ダイアログ中央表示
- Overlay
- 表示・非表示切り替え
では、順番に実装していきましょう。
ダイアログ中央表示
絶対位置で、ダイアログを中央に配置します。
index.html
<!DOCTYPE html>
<head>
<title>Modal App</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="dialog">Dialog</div>
</body>
style.css
#dialog {
position: fixed; /* 絶対位置で表示 */
top: 50%; /* 上端を中央に */
left: 50%; /* 左端を中央に */
/* 上記までで、エレメント左上が中央に位置することになる*/
/* 再配置を行うtranslateで、エレメントをその大きさの半分ずつ左と上にずらす*/
/* これにより、エレメントの中心がWindowの中心に位置することになる。*/
transform: translate(-50%, -50%);
width: 30%;
height: 30%;
border: 1px solid black;
background-color: lightblue;
}
Overlay
ダイアログの背面にシートを敷くイメージです。
index.html
<!DOCTYPE html>
<head>
<title>Modal App</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="dialog">Dialog</div>
+ <div id="overlay"></div>
</body>
style.css
#dialog {
position: fixed; /* 絶対位置で表示 */
top: 50%; /* 上端を中央に */
left: 50%; /* 左端を中央に */
/* 上記までで、エレメント左上が中央に位置することになる*/
/* 再配置を行うtranslateで、エレメントをその大きさの半分ずつ左と上にずらす*/
/* これにより、エレメントの中心がWindowの中心に位置することになる。*/
+ z-index: 1000; /* 他の要素よりも手前に表示する */
transform: translate(-50%, -50%);
width: 30%;
height: 30%;
border: 1px solid black;
background-color: lightblue;
}
/* 追加 */
#overlay {
position: fixed; /* 絶対位置で表示 */
/* 画面全体を覆う */
/* Browser windowの左上から、縦横一面の大きさを設定し配置*/
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999; /* 他の要素よりも手前に表示する。ただし、ダイアログの背面 */
background-color: lightgray;
}
表示・非表示
JavaScriptによる制御を組み込みます
また、ダイアログ表示にちょっとした動きを取り入れます。
index.html
<!DOCTYPE html>
<head>
<title>Modal App</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="dialog">Dialog</div>
<div id="overlay" />
+ <button id="open-button">Open</button>
+ <script src="index.js"></script>
</body>
style.css
#dialog {
+ /* 初期状態では非表示 */
+ opacity: 0;
+ visibility: hidden;
+ /* 0.3sかけて、表示・非表示が切り替わります。 */
+ transition: all 0.3s ease-out;
position: fixed; /* 絶対位置で表示 */
top: 50%; /* 上端を中央に */
left: 50%; /* 左端を中央に */
/* 上記までで、エレメント左上が中央に位置することになる */
/* 再配置を行うtranslateで、エレメントをその大きさの半分ずつ左と上にずらす */
/* これにより、エレメントの中心がWindowの中心に位置することになる。*/
z-index: 1000; /* 他の要素よりも手前に表示する */
transform: translate(-50%, -50%);
width: 30%;
height: 30%;
border: 1px solid black;
background-color: lightblue;
}
#overlay {
+ /* 初期状態では非表示 */
+ /* visibility: hidden;を設定することでOpenボタンを活性にできます。*/
+ opacity: 0;
+ visibility: hidden;
+ transition: all 0.3s ease-out;
position: fixed; /* 絶対位置で表示 */
/* 画面全体を覆う */
/* Browser windowの左上から、縦横一面の大きさを設定し配置 */
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999; /* 他の要素よりも手前に表示する。ただし、ダイアログの背面 */
background-color: lightgray;
}
/* 追加 */
#open-button {
cursor: pointer;
border: 1px solid #000;
margin: 10px;
}
index.js
// エレメントを取得
const dialog = document.getElementById('dialog');
const overlay = document.getElementById('overlay');
const openButton = document.getElementById('open-button');
// Scrollを固定するためのエレメント
const body = document.body;
// 表示処理
openButton.addEventListener('click', open);
function open() {
dialog.style.opacity = 1;
dialog.style.visibility = 'visible';
overlay.style.opacity = 1;
overlay.style.visibility = 'visible';
body.style.overflow = 'hidden';
}
// 非表示処理
overlay.addEventListener('click', close);
function close() {
dialog.style.opacity = 0;
dialog.style.visibility = 'hidden';
overlay.style.opacity = 0;
overlay.style.visibility = 'hidden';
body.style.overflow = 'auto';
}
最後に
この仕組みを理解していると、アカウント登録ダイアログがPopupして、続きが見れない系のモーダルを・・・
ということもできてしまいます。
Browser上のリソースは、基本的に見られてしまう・変更できてしまうということは忘れたくないですね。
また、実際のアプリケーションにおいては、"車輪の再発明"は必要ないです。
可能な限りよく使われているライブラリを使用しましょう!
あと、不勉強でしたが、Dialogタグも使えるようになっているようです!