武田構築:開発作業日記と備忘録

ウェブ関連の開発や周辺技術の備忘録です。

HTML確認ダイアログを構築

HTML組んでてちょっと自前のダイアログ表示が必要になり、作ってみたので備忘録的に内容をまとめます。

ネイティブJavaScriptとCSS3で、簡単なアニメーション込みの物になります。一応多分昨今のダイアログ表示も似たような作り方してるんじゃないかと思います。

<01 テスト用のHTMLを用意>

とりあえずダイアログテスト構築の為の必要最低限のHTMLを用意します。
ボタンをクリックすると表示する想定です。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8" />
    <title>ダイアログ構築テスト</title>
    <style>
        body {
            margin: 0; padding: 0px;
        }
        
        h3 {
            margin: 8px; padding: 0px;
        }
        
        button {
            margin: 8px; padding: 2px 8px 2px 8px;
        }
    </style>
</head>
<body>
    <h3 id="id01">ダイアログ表示</h3>
    <button type="button" id="dialogOpen">表示</button>
</body>
</html>

<02 ダイアログ表示用に全体を覆うDIVを用意>

画面の他の入力も抑制する事も兼ねて、画面全体を覆うDIVを設定します。
これがダイアログを入れるコンテナにもなります。
position: fixed;で浮かせます。top: 0; left: 0;で左上に固定。width: 100vw; height: 100vh;で画面全体を覆うサイズに、背景色はrgba()で半透明を指定、そしてFlexboxで内部要素が中央揃えになるようにしておきます。

CSS

    #testDialog {
        box-sizing: border-box;
        position: fixed; top: 0; left: 0;
        width: 100vw; height: 100vh;
        background-color: rgba(0, 0, 0, 0.2);
        display: flex;
        justify-content: center;
        align-items: center;
    }

HTML

<body>
    <h3 id="id01">ダイアログ表示</h3>
    <button type="button" id="dialogOpen">表示</button>
    <!-- 確認ダイアログ -->
    <div id="testDialog">
    </div>
</body>

<03 ダイアログ本体を設定>

ダイアログの本体を、先ほどの全体を覆うDIVの中に配置します。そしてサイズやレイアウトをCSSで調整します。(表示切替などは後ほど実装します)

CSS

    #testDialog .dialogFrame {
        padding: 8px;
        width: 400px; height: 300px;
        border: 2px solid #555555;
        border-radius: 12px;
        background-color: #ffffff;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        align-items: stretch;
    }
    
    #testDialog .commentArea {
        padding-top: 20px;
        display: flex;
        justify-content: center;
        align-items: center;
        flex-grow: 1;
    }
    
    #testDialog .buttonArea {
        height: 80px;
        display: flex;
        justify-content: space-around;
        align-items: center;
        flex-grow: 0;
    }
    
    #testDialog .dialogButton {
        width: 136px; height: 32px;
    }

HTML

<body>
    <h3 id="id01">ダイアログ表示</h3>
    <button type="button" id="dialogOpen">表示</button>
    <!-- 確認ダイアログ -->
    <div id="testDialog">
        <div id="testDialogFrame" class="dialogFrame">
            <div class="commentArea">
                <p>Dialog</p>
            </div>
            <div class="buttonArea">
                <button type="button" id="buttonCancel" class="dialogButton">Cancel</button>
                <button type="button" id="buttonOk" class="dialogButton">OK</button>
            </div>
        </div>
    </div>
</body>

<04 スクリプトで表示、非表示の切り替えを設定>

各ボタンで表示と非表示を切り替えれるよう、スクリプトを追加します。(アニメーションは最後の方で設定します)

CSS ※#testDialogを修正

    #testDialog {
        box-sizing: border-box;
        position: fixed; top: 0; left: 0;
        width: 100vw; height: 100vh;
        background-color: rgba(0, 0, 0, 0.2);
        /* display: flex; */
        display: none; /* 初期値をnoneにして非表示に */
        justify-content: center;
        align-items: center;
    }

HTML

<body>
    <h3 id="id01">ダイアログ表示</h3>
    <button type="button" id="dialogOpen">表示</button>
    <!-- 確認ダイアログ -->
    <div id="testDialog">
        <div id="testDialogFrame" class="dialogFrame">
            <div class="commentArea">
                <p>Dialog</p>
            </div>
            <div class="buttonArea">
                <button type="button" id="buttonCancel" class="dialogButton">Cancel</button>
                <button type="button" id="buttonOk" class="dialogButton">OK</button>
            </div>
        </div>
    </div>
    <!-- Script -->
    <script>
        // testDialog と testDialogFrame を控える
        var _dialog = document.getElementById("testDialog");
        var _dialogFrame = document.getElementById("testDialogFrame");

        // 関数定義
        function DialogOpen() {
            // noneからflexに変更
            _dialog.style.display = "flex";
        }

        function DialogClose() {
            // flexからnoneに変更
            _dialog.style.display = "none";
        }

        function DialogOK() {
            // とりあえずアラートでOKを表示
            alert("OK!");
        }

        // DOMが全部読み込まれた時のイベントを設定
        document.addEventListener("DOMContentLoaded", function() {
            // ボタンにクリックイベントを設定
            document.getElementById("dialogOpen").addEventListener("click", DialogOpen);
            document.getElementById("buttonCancel").addEventListener("click", DialogClose);
            document.getElementById("buttonOk").addEventListener("click", DialogOK);
        });
    </script>
</body>

ボタンで表示、非表示が切り替わるようになります。

<05 イン、アウトアニメーションを設定>

CSSで全体のフェードイン、フェードアウトと、ダイアログ部分のズームイン、ズームアウトのアニメーションを設定します。
スクリプトでクラスを切り替える事で実現します。
ブラウザのバージョン次第でフェードアウト時にdispley: none;がキーフレーム上で動かない可能性がありそうなので、別途setTimeout()で対応します。

CSS

    /* --- effect css --- */
    .dialog_fade_in {
        animation: dialogFadeIn 0.5s;
        animation-fill-mode: forwards;
    }
    
    .frame_zoom_in {
        animation: frameZoomIn 0.5s;
        animation-fill-mode: forwards;
    }

    .dialog_fade_out {
        animation: dialogFadeOut 0.5s;
        animation-fill-mode: forwards;
    }

    .frame_zoom_out {
        animation: frameZoomOut 0.5s;
        animation-fill-mode: forwards;
    }

    @keyframes dialogFadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
    }

    @keyframes frameZoomIn {
        from { transform: scale(0.5); }
        to { transform: scale(1.0); }
    }

    @keyframes dialogFadeOut {
        from { opacity: 1; }
        to { opacity: 0; }
    }

    @keyframes frameZoomOut {
        from { transform: scale(1.0); }
        to { transform: scale(0.5); }
    }

HTML

    <!-- Script -->
    <script>
        // testDialog と testDialogFrame を控える
        var _dialog = document.getElementById("testDialog");
        var _dialogFrame = document.getElementById("testDialogFrame");

        // 関数定義
        function DialogOpen() {
            // noneからflexに変更
            _dialog.style.display = "flex";
            // クラスを dialog_fade_in に変更
            _dialog.className = "dialog_fade_in";
            _dialogFrame.className = "dialogFrame frame_zoom_in";
        }

        function DialogClose() {
            // クラスを dialog_fade_out に変更
            _dialog.className = "dialog_fade_out";
            _dialogFrame.className = "dialogFrame frame_zoom_out";
            // displayプロパティが最近のブラウザじゃないとkeyframesで設定出来ないようなのでスクリプトで時間差設定
            setTimeout(()=>{ _dialog.style.display = "none"; }, 500);
        }

        function DialogOK() {
            // とりあえずアラートでOKを表示
            alert("OK!");
        }

        // DOMが全部読み込まれた時のイベントを設定
        document.addEventListener("DOMContentLoaded", function() {
            // ボタンにクリックイベントを設定
            document.getElementById("dialogOpen").addEventListener("click", DialogOpen);
            document.getElementById("buttonCancel").addEventListener("click", DialogClose);
            document.getElementById("buttonOk").addEventListener("click", DialogOK);
        });
    </script>
<06 完成>

あとはここから移植したりカスタマイズしていけば良いのではないかと思います。

サンプルページ(武田制作のサイト上に保存してます)

最終的なHTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8" />
    <title>ダイアログ構築テスト</title>
    <style>
        body {
            margin: 0; padding: 0px;
        }

        h3 {
            margin: 8px; padding: 0px;
        }

        button {
            margin: 8px; padding: 2px 8px 2px 8px;
        }

        #testDialog {
            box-sizing: border-box;
            position: fixed; top: 0; left: 0;
            width: 100vw; height: 100vh;
            background-color: rgba(0, 0, 0, 0.2);
            /* display: flex; */
            display: none; /* 初期値をnoneにして非表示に */
            justify-content: center;
            align-items: center;
        }

        #testDialog .dialogFrame {
            padding: 8px;
            width: 400px; height: 300px;
            border: 2px solid #555555;
            border-radius: 12px;
            background-color: #ffffff;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            align-items: stretch;
        }

        #testDialog .commentArea {
            padding-top: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-grow: 1;
        }

        #testDialog .buttonArea {
            height: 80px;
            display: flex;
            justify-content: space-around;
            align-items: center;
            flex-grow: 0;
        }

        #testDialog .dialogButton {
            width: 136px; height: 32px;
        }

        /* --- effect css --- */
        .dialog_fade_in {
            /* display: flex; ※何故かここで動かないのでスクリプトで直接指定する */
            animation: dialogFadeIn 0.5s;
            animation-fill-mode: forwards;
        }

        .frame_zoom_in {
            animation: frameZoomIn 0.5s;
            animation-fill-mode: forwards;
        }

        .dialog_fade_out {
            animation: dialogFadeOut 0.5s;
            animation-fill-mode: forwards;
        }

        .frame_zoom_out {
            animation: frameZoomOut 0.5s;
            animation-fill-mode: forwards;
        }

        @keyframes dialogFadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes frameZoomIn {
            from { transform: scale(0.5); }
            to { transform: scale(1.0); }
        }

        @keyframes dialogFadeOut {
            from { opacity: 1; }
            to { opacity: 0; }
        }

        @keyframes frameZoomOut {
            from { transform: scale(1.0); }
            to { transform: scale(0.5); }
        }
    </style>
</head>
<body>
    <h3 id="id01">ダイアログ表示</h3>
    <button type="button" id="dialogOpen">表示</button>
    <!-- 確認ダイアログ -->
    <div id="testDialog">
        <div id="testDialogFrame" class="dialogFrame">
            <div class="commentArea">
                <p>Dialog</p>
            </div>
            <div class="buttonArea">
                <button type="button" id="buttonCancel" class="dialogButton">Cancel</button>
                <button type="button" id="buttonOk" class="dialogButton">OK</button>
            </div>
        </div>
    </div>
    <!-- Script -->
    <script>
        // testDialog と testDialogFrame を控える
        var _dialog = document.getElementById("testDialog");
        var _dialogFrame = document.getElementById("testDialogFrame");

        // 関数定義
        function DialogOpen() {
            // noneからflexに変更
            _dialog.style.display = "flex";
            // クラスを dialog_fade_in に変更
            _dialog.className = "dialog_fade_in";
            _dialogFrame.className = "dialogFrame frame_zoom_in";
        }

        function DialogClose() {
            // クラスを dialog_fade_out に変更
            _dialog.className = "dialog_fade_out";
            _dialogFrame.className = "dialogFrame frame_zoom_out";
            // displayプロパティが最近のブラウザじゃないとkeyframesで設定出来ないようなのでスクリプトで時間差設定
            setTimeout(()=>{ _dialog.style.display = "none"; }, 500);
        }

        function DialogOK() {
            // とりあえずアラートでOKを表示
            alert("OK!");
        }

        // DOMが全部読み込まれた時のイベントを設定
        document.addEventListener("DOMContentLoaded", function() {
            // ボタンにクリックイベントを設定
            document.getElementById("dialogOpen").addEventListener("click", DialogOpen);
            document.getElementById("buttonCancel").addEventListener("click", DialogClose);
            document.getElementById("buttonOk").addEventListener("click", DialogOK);
        });
    </script>
</body>
</html>