【HTML】dialogタグの使い方:モーダルウィンドウや枠外クリック・CSS装飾

html-dialog-tag
ポートフォリオ向けサーバー
HTML/CSSスキルが活きる!
学んだ知識を活かして、
自分だけのブログを始めませんか?

WordPressブログなら、あなたのコーディング知識でデザインのカスタマイズが自由自在。
ブログデビューに最適な初心者向けサーバー環境を徹底比較しました。

HTMLの<dialog>タグを使えば、外部ライブラリに頼ることなく、ブラウザ標準機能だけでモーダルウィンドウを実装できます。

本記事では、基本の開閉処理、CSSによるカスタマイズ、スクロール制御やアクセシビリティ対応まで実務で役立つ実装手法を解説します。

ポップアップ・モーダルウィンドウのデザインコードが欲しい人は「【html&css】画面中央表示!ポップアップ・モーダルウィンドウデザイン2選」を一読ください。

HTML/CSS学習者の方へ
「学んだコード、自分のブログで試してみませんか?」
多くのブロガーがデザインでつまずく中、コードが読めるあなたは圧倒的に有利です。
自由自在なサイト構築の第一歩となる、初心者向けサーバーを分かりやすく比較しました。

\ スキルを活かして情報発信 / ブログ向けレンタルサーバー4選を読む▶︎
目次

dialogタグとは:基本の書き方

dialogとは、ブラウザがネイティブに提供するダイアログウィンドウを作成する専用タグです。

ここでは、dialogタグの使い方、専用のJavaScriptメソッドを利用したUIコンポーネントの設計、モーダルと非モーダルの違いを解説します。

dialogタグとは:基本の書き方
  • dialogタグの役割
  • showshowModalの違い
  • JavaScriptなしで開く方法

dialogタグの役割

<dialog>タグは、ポップアップやアラート、入力フォームなど、ユーザーの注意を引きたいサブウィンドウを構築する役割を担います。

📦 dialogタグの基本構造

⭕️ HTMLにタグを置くだけでポップアップの「箱」が完成

お知らせ

これはdialogタグで作られたウィンドウです。

<!– 💡 1. ダイアログの「箱」を作る –>
<dialog id=”myDialog”>
  <h2>お知らせ</h2>
  <p>これはdialogタグで作られたウィンドウです。</p>
  <!– 閉じるためのボタン –>
  <button id=”closeBtn”>閉じる</button>
</dialog>

/* 💡 2. JSでAPI(メソッド)を呼び出して操作する */
const dialog = document.getElementById(‘myDialog’);
// 開く処理(詳細は次の見出しで解説)
dialog.showModal();
// 閉じる処理
dialog.close();
HTMLコード表示
<div class="hdlg-sec1-wrapper">
  <div class="hdlg-sec1-demo-area">
    <div class="hdlg-sec1-box">
      <div class="hdlg-sec1-label">📦 dialogタグの基本構造</div>
      
      <div class="hdlg-sec1-visual">
        <p style="font-size:12px; color:#198754; font-weight:bold; margin:0 0 5px 0;">⭕️ HTMLにタグを置くだけでポップアップの「箱」が完成</p>
        
        <div class="hdlg-sec1-mock-bg">
          <div class="hdlg-sec1-mock-dialog">
            <div style="margin:0 0 10px 0;">お知らせ</div>
            <p style="font-size:12px; margin:0 0 15px 0;">これはdialogタグで作られたウィンドウです。</p>
            <button class="hdlg-sec1-btn">閉じる</button>
          </div>
        </div>
      </div>

      <div class="hdlg-sec1-code">
        <!-- 💡 1. ダイアログの「箱」を作る --><br>
        <span class="hdlg-sec1-hl-blue"><dialog id="myDialog"></span><br>
          <h2>お知らせ</h2><br>
          <p>これはdialogタグで作られたウィンドウです。</p><br>
          <span class="hdlg-sec1-hl-comment"><!-- 閉じるためのボタン --></span><br>
          <button id="closeBtn">閉じる</button><br>
        <span class="hdlg-sec1-hl-blue"></dialog></span><br><br>

        /* 💡 2. JSでAPI(メソッド)を呼び出して操作する */<br>
        <span class="hdlg-sec1-hl-blue">const</span> dialog = document.getElementById(<span class="hdlg-sec1-hl-green">'myDialog'</span>);<br>
        <span class="hdlg-sec1-hl-comment">// 開く処理(詳細は次の見出しで解説)</span><br>
        dialog.<span class="hdlg-sec1-hl-red">showModal()</span>;<br>
        <span class="hdlg-sec1-hl-comment">// 閉じる処理</span><br>
        dialog.<span class="hdlg-sec1-hl-red">close()</span>;
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-sec1-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-sec1-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-sec1-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-sec1-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-sec1-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
}
.hdlg-sec1-mock-bg {
  background-color: rgba(0, 0, 0, 0.5);
  padding: 30px;
  border-radius: 4px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.hdlg-sec1-mock-dialog {
  background-color: #fff;
  padding: 20px;
  border-radius: 6px;
  box-shadow: 0 4px 10px rgba(0,0,0,0.2);
  min-width: 200px;
}
.hdlg-sec1-btn {
  background-color: #e9ecef;
  border: 1px solid #ced4da;
  padding: 5px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-sec1-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
}
.hdlg-sec1-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-sec1-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-sec1-hl-red {
  color: #e06c75;
  font-weight: bold;
}
.hdlg-sec1-hl-comment {
  color: #6c757d;
  font-style: italic;
}

showとshowModalの違い

<dialog>タグを使いこなす上で重要なのが、ダイアログを開く2つのJavaScriptメソッドの違いを正しく理解することです。

  • show()メソッド
    非モーダル。
    ダイアログは開きますが、ユーザーは後ろにある画面のリンクをクリック・操作できます。
    「小さな通知」などに使います。
  • showModal()メソッド
    モーダル。
    開いている間、後ろの画面の操作はブロックされます。
    ブラウザが自動的に背景を暗くする::backdrop疑似要素を提供し、ESCキーで閉じる機能も装備されます。
    「入力フォーム」や「警告」にはこちらを使います。
⚖️ show() と showModal() の違い

ボタンを押して違いを確かめてください

※ダイアログ表示中、この文字を選択できるか試してください。

非モーダル(show)

背景は暗くならず、後ろの操作も可能です。

モーダル(showModal)

背景が暗くなり、後ろの操作はブロックされます。
※ESCキーでも閉じられます。

/* ❌ 悪い例:背景を自作しようとしている */
dialog.show();
document.getElementById(‘overlay’).style.display = ‘block’;

/* ⭕️ 正解:showModalを使えばブラウザが全部やってくれる */
dialog.showModal();

/* 背景(バックドロップ)の色を変えたい場合のCSS */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.8);
}
HTMLコード表示
<div class="hdlg-sec2-wrapper">
  <div class="hdlg-sec2-demo-area">
    <div class="hdlg-sec2-box">
      <div class="hdlg-sec2-label">⚖️ show() と showModal() の違い</div>
      
      <div class="hdlg-sec2-visual">
        <p style="font-size:12px; font-weight:bold; margin:0 0 10px 0;">ボタンを押して違いを確かめてください</p>
        
        <div style="display:flex; gap:10px; margin-bottom:15px;">
          <button id="btnShow" class="hdlg-sec2-btn-show">show() で開く</button>
          <button id="btnShowModal" class="hdlg-sec2-btn-modal">showModal() で開く</button>
        </div>
        
        <p style="font-size:11px; color:#666; margin:0;">※ダイアログ表示中、この文字を選択できるか試してください。</p>

        <dialog id="dialogShow" class="hdlg-sec2-dialog">
          <div style="margin:0 0 10px 0; color:#0d6efd;">非モーダル(show)</div>
          <p style="font-size:12px;">背景は暗くならず、後ろの操作も可能です。</p>
          <button id="btnCloseShow" class="hdlg-sec2-btn">閉じる</button>
        </dialog>

        <dialog id="dialogShowModal" class="hdlg-sec2-dialog">
          <div style="margin:0 0 10px 0; color:#dc3545;">モーダル(showModal)</div>
          <p style="font-size:12px;">背景が暗くなり、後ろの操作はブロックされます。<br>※ESCキーでも閉じられます。</p>
          <button id="btnCloseModal" class="hdlg-sec2-btn">閉じる</button>
        </dialog>
      </div>

      <div class="hdlg-sec2-code">
        <span class="hdlg-sec2-hl-comment">/* ❌ 悪い例:背景を自作しようとしている */</span><br>
        dialog.<span class="hdlg-sec2-hl-red">show()</span>;<br>
        document.getElementById('overlay').style.display = 'block';<br><br>

        <span class="hdlg-sec2-hl-comment">/* ⭕️ 正解:showModalを使えばブラウザが全部やってくれる */</span><br>
        dialog.<span class="hdlg-sec2-hl-green">showModal()</span>;<br><br>

        <span class="hdlg-sec2-hl-comment">/* 背景(バックドロップ)の色を変えたい場合のCSS */</span><br>
        <span class="hdlg-sec2-hl-blue">dialog::backdrop</span> {<br>
          <span class="hdlg-sec2-hl-green">background-color: rgba(0, 0, 0, 0.8);</span><br>
        }
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-sec2-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-sec2-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-sec2-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-sec2-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-sec2-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
}
.hdlg-sec2-btn-show {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-sec2-btn-modal {
  background-color: #dc3545;
  color: #fff;
  border: none;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-sec2-btn {
  background-color: #e9ecef;
  border: 1px solid #ced4da;
  padding: 5px 15px;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 10px;
}
.hdlg-sec2-dialog {
  border: none;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
/* showModal時の背景色カスタマイズ */
.hdlg-sec2-dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
}
.hdlg-sec2-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}
.hdlg-sec2-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-sec2-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-sec2-hl-red {
  color: #e06c75;
  font-weight: bold;
}
.hdlg-sec2-hl-comment {
  color: #6c757d;
  font-style: italic;
}
JavaScriptコード表示
setTimeout(() => {
  const dialogShow = document.getElementById('dialogShow');
  const dialogShowModal = document.getElementById('dialogShowModal');
  const btnShow = document.getElementById('btnShow');
  const btnShowModal = document.getElementById('btnShowModal');
  const btnCloseShow = document.getElementById('btnCloseShow');
  const btnCloseModal = document.getElementById('btnCloseModal');

  if(btnShow && dialogShow) {
    btnShow.addEventListener('click', () => dialogShow.show());
    btnCloseShow.addEventListener('click', () => dialogShow.close());
    
    btnShowModal.addEventListener('click', () => dialogShowModal.showModal());
    btnCloseModal.addEventListener('click', () => dialogShowModal.close());
  }
}, 100);

JavaScriptなしで開く方法

「ページを開いた瞬間に、最初からお知らせを表示しておきたい」という場合、JavaScriptを使わずに表示させる方法がHTMLに用意されています。

それが<dialog>タグへのopen属性の追加です。

JavaScriptなしで開くopen属性は、あくまでページの一部に初めから表示しておく「非モーダルな案内版」として割り切って使用します。

また、open属性だけで開いたダイアログは、閉じるJavaScript(close())を書かない限り画面に残り続けます。

(※HTMLの<form method="dialog">を使えばJSなしでも閉じられますが、用途が限定的です。)

初期表示で「モーダル(背景暗転)」を出したい場合は、ページ読み込み直後にJavaScriptでdialog.showModal()を実行するのがよいです。

🚪 JSなしで開く open属性の仕様

⭕️ HTMLに属性を書くだけで最初から表示されます

メンテナンスのお知らせ

※open属性で開いた場合は、必ず「非モーダル」になります。

(背景は暗くならない)

<!– ❌ 間違い:open属性でモーダル(背景暗転)にはならない –>
<dialog open>重要なお知らせ</dialog>

<!– ⭕️ 完璧:HTMLの標準機能のみで「閉じる」ボタンを実装 –>
<dialog open>
  <p>お知らせ内容</p>
  <!– ★ form method=”dialog” 内のボタンは、押すとダイアログを閉じる –>
  <form method=”dialog”>
    <button>JSなしで閉じる</button>
  </form>
</dialog>
HTMLコード表示
<div class="hdlg-sec3-wrapper">
  <div class="hdlg-sec3-demo-area">
    <div class="hdlg-sec3-box">
      <div class="hdlg-sec3-label">🚪 JSなしで開く open属性の仕様</div>
      
      <div class="hdlg-sec3-visual">
        <p style="font-size:12px; color:#0d6efd; font-weight:bold; margin:0 0 5px 0;">⭕️ HTMLに属性を書くだけで最初から表示されます</p>
        
        <div class="hdlg-sec3-mock-bg">
          <dialog open class="hdlg-sec3-mock-dialog">
            <div style="margin:0 0 5px 0; font-size:14px;">メンテナンスのお知らせ</div>
            <p style="font-size:11px; margin:0; color:#555;">※open属性で開いた場合は、必ず「非モーダル」になります。</p>
          </dialog>
          
          <p style="font-size:11px; color:#666; text-align:center; margin-top:80px;">(背景は暗くならない)</p>
        </div>
      </div>

      <div class="hdlg-sec3-code">
        <!-- ❌ 間違い:open属性でモーダル(背景暗転)にはならない --><br>
        <dialog open>重要なお知らせ</dialog><br><br>

        <!-- ⭕️ 完璧:HTMLの標準機能のみで「閉じる」ボタンを実装 --><br>
        <dialog <span class="hdlg-sec3-hl-green">open</span>><br>
          <p>お知らせ内容</p><br>
          <span class="hdlg-sec3-hl-comment"><!-- ★ form method="dialog" 内のボタンは、押すとダイアログを閉じる --></span><br>
          <span class="hdlg-sec3-hl-blue"><form method="dialog"></span><br>
            <button>JSなしで閉じる</button><br>
          <span class="hdlg-sec3-hl-blue"></form></span><br>
        </dialog>
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-sec3-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-sec3-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-sec3-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-sec3-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-sec3-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
}
.hdlg-sec3-mock-bg {
  background-color: #e9ecef;
  border: 1px dashed #adb5bd;
  border-radius: 4px;
  position: relative;
  height: 120px;
}
.hdlg-sec3-mock-dialog {
  display: block; /* open状態の再現 */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #fff;
  border: 1px solid #ced4da;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
  width: 80%;
  margin: 0;
}
.hdlg-sec3-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}
.hdlg-sec3-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-sec3-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-sec3-hl-red {
  color: #e06c75;
  font-weight: bold;
}
.hdlg-sec3-hl-comment {
  color: #6c757d;
  font-style: italic;
}

JavaScriptを使ったdialogの開閉とイベント

<dialog>要素の真価は、JavaScriptと組み合わせた際の強力な標準APIにあります。

従来のライブラリに頼ることなく、ブラウザ標準の機能だけでモーダルの挙動を制御できるのがメリットです。

表示・非表示を切り替えるだけでなく、イベントハンドリングを正しく理解することで、ユーザーの操作に合わせた柔軟なUIを構築できます。

ここでは3つの実装パターンを解説します。

JavaScriptを使ったdialogの開閉とイベント
  • 開くと閉じる処理
  • 閉じるイベントの取得
  • 背景クリックで閉じる実装方法

開くと閉じる処理

ダイアログを制御する基本は、JSのメソッド呼び出しです。

特に「閉じるボタン」を設置して、ユーザーが明示的に閉じられるようにすることはアクセシビリティの観点からも必須です。

ダイアログの開閉にはshowModal()(またはshow())とclose()メソッドを使用しましょう。

🔘 showModalとcloseの制御

標準APIで正しく制御されています。

/* ⭕️ 正しい制御方法 */
const dialog = document.getElementById(‘js1-dialog’);

// 開く処理
openBtn.addEventListener(‘click’, () => {
  dialog.showModal();
});

// 閉じる処理
closeBtn.addEventListener(‘click’, () => {
  dialog.close();
});
HTMLコード表示
<div class="hdlg-js1-wrapper">
  <div class="hdlg-js1-demo-area">
    <div class="hdlg-js1-box">
      <div class="hdlg-js1-label">🔘 showModalとcloseの制御</div>
      
      <div class="hdlg-js1-visual">
        <button id="js1-open" class="hdlg-js1-btn-main">モーダルを開く</button>
      </div>

      <dialog id="js1-dialog" class="hdlg-js1-dialog">
        <div class="hdlg-js1-inner">
          <p>標準APIで正しく制御されています。</p>
          <button id="js1-close" class="hdlg-js1-btn-sub">閉じる</button>
        </div>
      </dialog>

      <div class="hdlg-js1-code">
        /* ⭕️ 正しい制御方法 */<br>
        const dialog = document.getElementById('js1-dialog');<br><br>
        
        // 開く処理<br>
        openBtn.addEventListener('click', () => {<br>
          <span class="hdlg-js1-hl-green">dialog.showModal();</span><br>
        });<br><br>
        
        // 閉じる処理<br>
        closeBtn.addEventListener('click', () => {<br>
          <span class="hdlg-js1-hl-green">dialog.close();</span><br>
        });
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-js1-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-js1-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-js1-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-js1-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-js1-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}
.hdlg-js1-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-js1-btn-sub {
  background-color: #6c757d;
  color: #fff;
  border: none;
  padding: 5px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-js1-dialog {
  margin: auto;
  border: none;
  border-radius: 8px;
  padding: 0;
  box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
.hdlg-js1-inner {
  padding: 30px;
  text-align: center;
}
.hdlg-js1-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
}
.hdlg-js1-hl-green {
  color: #98c379;
  font-weight: bold;
}
JavaScriptコード表示
setTimeout(() => {
  const d = document.getElementById('js1-dialog');
  const o = document.getElementById('js1-open');
  const c = document.getElementById('js1-close');
  if(o && d) o.onclick = () => d.showModal();
  if(c && d) c.onclick = () => d.close();
}, 100);

閉じるイベントの取得

ダイアログが閉じられたことを検知して特定の処理を行いたい場合、dialogタグの閉じるイベントを利用します。

終了時の処理はボタンのクリックイベントではなく、<dialog>要素そのもののcloseイベントに対して設定しましょう。

また、dialog.close("戻り値")のように引数を渡すと、dialog.returnValueプロパティから「はい」「いいえ」などの選択結果を取得できます。

📝 closeイベントと戻り値の取得

結果:未回答

この内容で送信しますか?

// 閉じる時に値を渡す
dialog.close(‘yes’);

// ★閉じられたことを検知する
dialog.addEventListener(‘close’, () => {
  console.log(dialog.returnValue);
});
HTMLコード表示
<div class="hdlg-js2-wrapper">
  <div class="hdlg-js2-demo-area">
    <div class="hdlg-js2-box">
      <div class="hdlg-js2-label">📝 closeイベントと戻り値の取得</div>
      
      <div class="hdlg-js2-visual">
        <button id="js2-open" class="hdlg-js2-btn-main">アンケートに答える</button>
        <p id="js2-result" style="margin-top:15px; font-size:13px; color:#198754; font-weight:bold;">結果:未回答</p>
      </div>

      <dialog id="js2-dialog" class="hdlg-js2-dialog">
        <div class="hdlg-js2-inner">
          <p>この内容で送信しますか?</p>
          <div style="display:flex; gap:10px; justify-content:center;">
            <button class="js2-close-btn" data-val="yes" style="background:#198754; color:#fff; border:none; padding:5px 15px; border-radius:4px; cursor:pointer;">はい</button>
            <button class="js2-close-btn" data-val="no" style="background:#dc3545; color:#fff; border:none; padding:5px 15px; border-radius:4px; cursor:pointer;">いいえ</button>
          </div>
        </div>
      </dialog>

      <div class="hdlg-js2-code">
        // 閉じる時に値を渡す<br>
        dialog.close(<span class="hdlg-js2-hl-green">'yes'</span>);<br><br>
        
        // ★閉じられたことを検知する<br>
        dialog.addEventListener(<span class="hdlg-js2-hl-red">'close'</span>, () => {<br>
          console.log(dialog.<span class="hdlg-js2-hl-green">returnValue</span>);<br>
        });
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-js2-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}

.hdlg-js2-demo-area {
  display: flex;
  justify-content: center;
}

.hdlg-js2-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}

.hdlg-js2-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}

.hdlg-js2-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}

.hdlg-js2-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
}

.hdlg-js2-dialog {
  margin: auto;
  border: none;
  border-radius: 8px;
  padding: 0;
  box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}

.hdlg-js2-inner {
  padding: 30px;
}

.hdlg-js2-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}

.hdlg-js2-hl-green {
  color: #98c379;
  font-weight: bold;
}

.hdlg-js2-hl-red {
  color: #e06c75;
  font-weight: bold;
}
JavaScriptコード表示
setTimeout(() => {
  const d = document.getElementById('js2-dialog');
  const o = document.getElementById('js2-open');
  const r = document.getElementById('js2-result');
  if(o && d) o.onclick = () => d.showModal();
  document.querySelectorAll('.js2-close-btn').forEach(b => {
    b.onclick = () => d.close(b.dataset.val);
  });
  if(d) d.onclose = () => r.textContent = `結果:${d.returnValue === 'yes' ? '送信しました' : 'キャンセルしました'}`;
}, 100);

背景クリックで閉じる実装方法

モーダル表示の際、ダイアログの外側(薄暗い背景部分)をクリックしたら閉じるようにしたいという要望は多いです。

背景クリックを判定するには、clickイベントの発生場所(座標)を確認します。

ダイアログ要素に対してクリックイベントを設定し、クリックされた位置が「ダイアログの矩形(枠)」の外側であればclose()を実行するというロジックがスマートで一般的です。

🖱 背景クリックで閉じる判定

この「枠外」をクリックしてください

枠内をクリックしても閉じません。

dialog.addEventListener(‘click’, (e) => {
  // クリックされた要素がdialog自身(背景)か判定
  if (e.target === dialog) {
    dialog.close();
  }
});
HTMLコード表示
<div class="hdlg-js3-wrapper">
  <div class="hdlg-js3-demo-area">
    <div class="hdlg-js3-box">
      <div class="hdlg-js3-label">🖱 背景クリックで閉じる判定</div>
      
      <div class="hdlg-js3-visual">
        <button id="js3-open" class="hdlg-js3-btn-main">背景クリックを試す</button>
      </div>

      <dialog id="js3-dialog" class="hdlg-js3-dialog">
        <div class="hdlg-js3-inner">
          <p style="font-weight:bold;">この「枠外」をクリックしてください</p>
          <p style="font-size:12px; color:#666;">枠内をクリックしても閉じません。</p>
        </div>
      </dialog>

      <div class="hdlg-js3-code">
        dialog.addEventListener('click', (e) => {<br>
          <span class="hdlg-js3-hl-comment">// クリックされた要素がdialog自身(背景)か判定</span><br>
          if (e.target === <span class="hdlg-js3-hl-green">dialog</span>) {<br>
            dialog.close();<br>
          }<br>
        });
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-js3-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}

.hdlg-js3-demo-area {
  display: flex;
  justify-content: center;
}

.hdlg-js3-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}

.hdlg-js3-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}

.hdlg-js3-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}

.hdlg-js3-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
}

.hdlg-js3-dialog {
  margin: auto;
  border: none;
  border-radius: 8px;
  padding: 0;
  box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}

/* 背景を少し分かりやすく */
.hdlg-js3-dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
}

.hdlg-js3-inner {
  padding: 40px;
  background-color: #fff;
  pointer-events: auto;
}

.hdlg-js3-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}

.hdlg-js3-hl-green {
  color: #98c379;
  font-weight: bold;
}

.hdlg-js3-hl-comment {
  color: #6c757d;
  font-style: italic;
}
JavaScriptコード表示
setTimeout(() => {
  const d = document.getElementById('js3-dialog');
  const o = document.getElementById('js3-open');
  if(o && d) o.onclick = () => d.showModal();
  // 背景クリック判定:e.targetがdialog自身(子要素ではない)場合に閉じる
  if(d) d.addEventListener('click', (e) => { if (e.target === d) d.close(); });
}, 100);

ダイアログの作成(フォーム・確認画面)

JavaScriptでの基本的な開閉をマスターしたら、実際のWebアプリケーションで需要の高い「データ入力フォーム」や「実行確認」といった実用的なダイアログの作成になります。

ここでは、実務で使えるdialogのサンプル、CSSによるデザイン、javascriptの連携テクニックを解説します。

ダイアログの作成(フォーム・確認画面)
  • form method="dialog"の使い方
  • はい・いいえの確認画面の作成

form method=”dialog”の使い方

<dialog>タグには、フォームと連携する専用機能が用意されています。

ダイアログ内に<form method="dialog">を配置すると、その中の送信ボタンを押した瞬間にJavaScriptのclose()メソッドを書かなくても自動的にダイアログが閉じます。

入力されたデータを実際にサーバーへ送りたい場合は、ダイアログが閉じた後に発生するcloseイベントをJavaScriptでキャッチし、fetcXMLHttpRequest を使って非同期通信でデータを送信する設計にするのがよいです。

📝 form method=”dialog” の入力フォーム

入力結果がここに表示されます

プロフィール編集
<!– 💡 フォームのmethodを dialog に設定する –>
<form method=”dialog”>
  <input type=”text” name=”username”>

  <!– 💡 buttonのvalueがダイアログの戻り値になる –>
  <button type=”submit” value=”cancel” formnovalidate>キャンセル</button>
  <button type=”submit” value=”save”>保存</button>
</form>
HTMLコード表示
<div class="hdlg-prac1-wrapper">
  <div class="hdlg-prac1-demo-area">
    <div class="hdlg-prac1-box">
      <div class="hdlg-prac1-label">📝 form method="dialog" の入力フォーム</div>
      
      <div class="hdlg-prac1-visual">
        <button id="prac1-open" class="hdlg-prac1-btn-main">プロフィールを編集</button>
        <p id="prac1-result" style="margin-top:15px; font-size:13px; color:#666;">入力結果がここに表示されます</p>
      </div>

      <dialog id="prac1-dialog" class="hdlg-prac1-dialog">
        <div class="hdlg-prac1-inner">
          <div class="hdlg-prac1-title">プロフィール編集</div>
          
          <form method="dialog" id="prac1-form">
            <div class="hdlg-prac1-input-group">
              <label class="hdlg-prac1-label-text">ユーザー名</label>
              <input type="text" name="username" id="prac1-input" class="hdlg-prac1-input" placeholder="例:山田 太郎" required>
            </div>
            
            <div class="hdlg-prac1-actions">
              <button type="submit" value="cancel" class="hdlg-prac1-btn-cancel" formnovalidate>キャンセル</button>
              <button type="submit" value="save" class="hdlg-prac1-btn-submit">保存する</button>
            </div>
          </form>
        </div>
      </dialog>

      <div class="hdlg-prac1-code">
        <!-- 💡 フォームのmethodを dialog に設定する --><br>
        <form <span class="hdlg-prac1-hl-green">method="dialog"</span>><br>
          <input type="text" name="username"><br><br>
        
          <!-- 💡 buttonのvalueがダイアログの戻り値になる --><br>
          <button type="submit" <span class="hdlg-prac1-hl-blue">value="cancel"</span> formnovalidate>キャンセル</button><br>
          <button type="submit" <span class="hdlg-prac1-hl-blue">value="save"</span>>保存</button><br>
        </form>
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-prac1-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-prac1-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-prac1-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-prac1-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-prac1-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}
.hdlg-prac1-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}
.hdlg-prac1-dialog {
  margin: auto;
  border: none;
  border-radius: 8px;
  padding: 0;
  box-shadow: 0 10px 25px rgba(0,0,0,0.2);
}
.hdlg-prac1-dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.6);
}
.hdlg-prac1-inner {
  padding: 25px;
  width: 300px;
}
.hdlg-prac1-title {
  margin: 0 0 20px 0;
  font-size: 18px;
  color: #333;
}
.hdlg-prac1-input-group {
  margin-bottom: 20px;
  text-align: left;
}
.hdlg-prac1-label-text {
  display: block;
  font-size: 12px;
  font-weight: bold;
  margin-bottom: 5px;
  color: #555;
}
.hdlg-prac1-input {
  width: 100%;
  padding: 10px;
  border: 1px solid #ced4da;
  border-radius: 4px;
  box-sizing: border-box;
  font-size: 14px;
}
.hdlg-prac1-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
.hdlg-prac1-btn-cancel {
  background-color: #fff;
  border: 1px solid #ced4da;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
  color: #495057;
}
.hdlg-prac1-btn-submit {
  background-color: #198754;
  color: #fff;
  border: none;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-prac1-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}
.hdlg-prac1-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-prac1-hl-blue {
  color: #61afef;
  font-weight: bold;
}
JavaScriptコード表示
setTimeout(() => {
  const dialog = document.getElementById('prac1-dialog');
  const openBtn = document.getElementById('prac1-open');
  const resultText = document.getElementById('prac1-result');
  const inputEl = document.getElementById('prac1-input');

  if(openBtn && dialog) {
    openBtn.addEventListener('click', () => {
      dialog.showModal();
    });
  }

  if(dialog) {
    dialog.addEventListener('close', () => {
      // buttonのvalue属性の値('save' か 'cancel')が returnValue に入る
      if (dialog.returnValue === 'save') {
        resultText.textContent = `保存完了:${inputEl.value}`;
        resultText.style.color = '#198754';
      } else {
        resultText.textContent = 'キャンセルされました';
        resultText.style.color = '#dc3545';
      }
    });
  }
}, 100);

<form>タグの使い方を詳しく知りたい人は「【HTML】formタグの使い方:属性の書き方や複数送信・CSS装飾」を一読ください。

はい・いいえの確認画面の作成

「データを削除しますか?」「本当に退会しますか?」といった場面で、昔から使われるwindow.confirm()(ブラウザ標準のアラート)はデザインが変更できず、現代のサイトには馴染みません。

そこで<dialog>を使って、おしゃれな「はい/いいえ」の確認画面を自作します。

自作の確認ダイアログの「はい」「いいえ」の結果を待ってから次の処理へ進めるには、JavaScriptのPromiseを使ってダイアログをラップするのがよいです。

🚨 「はい/いいえ」のカスタムConfirm画面

処理結果がここに表示されます

⚠️
本当に削除しますか?

この操作は取り消すことができません。アカウント内のすべてのデータが永久に失われます。

<!– ❌ 致命的なミス:処理は止まらない –>
const result = dialog.showModal();
if(result) { … } // ← ユーザーが押す前に実行されてしまう

<!– ⭕️ 大正解:Promiseでユーザーの操作を「待つ」 –>
async function handleDelete() {
  // 自作の関数でダイアログの終了を待機
  const isConfirmed = await openConfirmDialog();

  if (isConfirmed === ‘true’) {
    console.log(“削除を実行しました”);
  }
}
HTMLコード表示
<div class="hdlg-prac2-wrapper">
  <div class="hdlg-prac2-demo-area">
    <div class="hdlg-prac2-box">
      <div class="hdlg-prac2-label">🚨 「はい/いいえ」のカスタムConfirm画面</div>
      
      <div class="hdlg-prac2-visual">
        <button id="prac2-open" class="hdlg-prac2-btn-main">アカウントを削除する</button>
        <p id="prac2-result" style="margin-top:15px; font-size:13px; color:#666;">処理結果がここに表示されます</p>
      </div>

      <dialog id="prac2-dialog" class="hdlg-prac2-dialog">
        <div class="hdlg-prac2-inner">
          <div class="hdlg-prac2-icon">⚠️</div>
          <div class="hdlg-prac2-title">本当に削除しますか?</div>
          <p class="hdlg-prac2-text">この操作は取り消すことができません。アカウント内のすべてのデータが永久に失われます。</p>
          
          <div class="hdlg-prac2-actions">
            <button class="hdlg-prac2-btn-cancel js-confirm-btn" value="false">キャンセル</button>
            <button class="hdlg-prac2-btn-danger js-confirm-btn" value="true">はい、削除します</button>
          </div>
        </div>
      </dialog>

      <div class="hdlg-prac2-code">
        <!-- ❌ 致命的なミス:処理は止まらない --><br>
        const result = dialog.showModal();<br>
        if(result) { ... } <span class="hdlg-prac2-hl-comment">// ← ユーザーが押す前に実行されてしまう</span><br><br>

        <!-- ⭕️ 大正解:Promiseでユーザーの操作を「待つ」 --><br>
        <span class="hdlg-prac2-hl-blue">async function</span> handleDelete() {<br>
          <span class="hdlg-prac2-hl-comment">// 自作の関数でダイアログの終了を待機</span><br>
          const isConfirmed = <span class="hdlg-prac2-hl-blue">await</span> openConfirmDialog();<br><br>
          if (isConfirmed === <span class="hdlg-prac2-hl-green">'true'</span>) {<br>
            console.log("削除を実行しました");<br>
          }<br>
        }
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-prac2-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-prac2-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-prac2-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-prac2-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-prac2-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}
.hdlg-prac2-btn-main {
  background-color: #dc3545;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}
.hdlg-prac2-dialog {
  border: none;
  border-radius: 12px;
  padding: 0;
  box-shadow: 0 10px 25px rgba(0,0,0,0.3);
}
.hdlg-prac2-dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(3px);
}
.hdlg-prac2-inner {
  padding: 30px;
  width: 320px;
  text-align: center;
}
.hdlg-prac2-icon {
  font-size: 40px;
  margin-bottom: 10px;
}
.hdlg-prac2-title {
  margin: 0 0 10px 0;
  font-size: 18px;
  color: #333;
}
.hdlg-prac2-text {
  font-size: 13px;
  color: #666;
  line-height: 1.5;
  margin: 0 0 25px 0;
}
.hdlg-prac2-actions {
  display: flex;
  gap: 10px;
}
.hdlg-prac2-btn-cancel {
  flex: 1;
  background-color: #e9ecef;
  color: #333;
  border: none;
  padding: 12px;
  border-radius: 6px;
  cursor: pointer;
  font-weight: bold;
}
.hdlg-prac2-btn-danger {
  flex: 1;
  background-color: #dc3545;
  color: #fff;
  border: none;
  padding: 12px;
  border-radius: 6px;
  cursor: pointer;
  font-weight: bold;
}
.hdlg-prac2-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #dc3545;
}
.hdlg-prac2-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-prac2-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-prac2-hl-comment {
  color: #6c757d;
  font-style: italic;
}
JavaScriptコード表示
setTimeout(() => {
  const dialog = document.getElementById('prac2-dialog');
  const openBtn = document.getElementById('prac2-open');
  const resultText = document.getElementById('prac2-result');
  const buttons = dialog.querySelectorAll('.js-confirm-btn');

  // Promiseを使ってダイアログをラップする関数
  function openCustomConfirm() {
    return new Promise((resolve) => {
      // ダイアログを表示
      dialog.showModal();

      // 一度だけ発火するイベントリスナーを登録
      const handleClose = () => {
        dialog.removeEventListener('close', handleClose);
        resolve(dialog.returnValue);
      };
      
      dialog.addEventListener('close', handleClose);
    });
  }

  // ボタンクリックで閉じる処理
  buttons.forEach(btn => {
    btn.addEventListener('click', (e) => {
      dialog.close(e.target.value);
    });
  });

  // メインの呼び出し処理(async/awaitを利用)
  if(openBtn) {
    openBtn.addEventListener('click', async () => {
      resultText.textContent = "待機中...";
      
      // ユーザーの選択を「待つ」
      const isConfirmed = await openCustomConfirm();
      
      if (isConfirmed === 'true') {
        resultText.textContent = "処理:削除を実行しました。";
        resultText.style.color = "#dc3545";
      } else {
        resultText.textContent = "処理:キャンセルされました。";
        resultText.style.color = "#6c757d";
      }
    });
  }
}, 100);

CSSでdialogをデザイン・カスタマイズする

<dialog>タグは標準状態で強力な機能を持ちますが、デフォルトの見た目はブラウザによって異なり、少し無骨な印象を与えます。

そのため、Webプロジェクトに導入する際は、CSSを駆使して、サイトに合わせたデザインを適用することが不可欠です。

ここでは、モーダルウィンドウの実装で直面する「サイズ・位置の調整」「背景の装飾」、ユーザー体験を向上させるアニメーションについて解説します。

CSSでdialogをデザイン・カスタマイズする
  • サイズ(幅)と表示位置(中央寄せ)の調整
  • 背景を暗くする・ぼかす設定
  • 開閉時のアニメーションの付け方

サイズ(幅)と表示位置(中央寄せ)の調整

ダイアログの見た目を整えるには、適切なサイズと幅を設定し、画面の正しい位置に配置することです。

ダイアログの配置はブラウザに任せ、CSSでは「幅(width/max-width)」と「内側の余白(padding)」だけを指定するのがよいです。

また、スマホ画面で全画面表示にしたい場合はwidth: 100vw; height: 100vh; max-width: none; max-height: none; margin: 0;のように、ブラウザのデフォルトマージンを打ち消す設定を行います。

📐 サイズと表示位置の調整
標準サイズ

max-widthを指定し、はみ出しを防ぎます。中央寄せはブラウザが自動で行います。

全画面表示

margin: 0; と width/height: 100%; で画面いっぱいに広げます。

/* ⭕️ 標準サイズ(位置指定は不要) */
dialog.normal {
  width: 90%;
  max-width: 500px;
  border: none;
}

/* ⭕️ 全画面表示(フルスクリーン) */
dialog.fullscreen {
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  margin: 0; /* ★ブラウザの自動マージンを消す */
}
HTMLコード表示
<div class="hdlg-css1-wrapper">
  <div class="hdlg-css1-demo-area">
    <div class="hdlg-css1-box">
      <div class="hdlg-css1-label">📐 サイズと表示位置の調整</div>
      
      <div class="hdlg-css1-visual">
        <div style="display:flex; gap:10px; justify-content:center;">
          <button id="css1-btn-normal" class="hdlg-css1-btn-main">標準サイズで開く</button>
          <button id="css1-btn-full" class="hdlg-css1-btn-sub">全画面(Full Screen)</button>
        </div>
      </div>

      <dialog id="css1-dialog-normal" class="hdlg-css1-dialog-normal">
        <div class="hdlg-css1-inner">
          <div style="margin-top:0;">標準サイズ</div>
          <p>max-widthを指定し、はみ出しを防ぎます。中央寄せはブラウザが自動で行います。</p>
          <button class="js-css1-close hdlg-css1-btn-close">閉じる</button>
        </div>
      </dialog>

      <dialog id="css1-dialog-full" class="hdlg-css1-dialog-full">
        <div class="hdlg-css1-inner-full">
          <div style="margin-top:0;">全画面表示</div>
          <p>margin: 0; と width/height: 100%; で画面いっぱいに広げます。</p>
          <button class="js-css1-close hdlg-css1-btn-close">閉じる</button>
        </div>
      </dialog>

      <div class="hdlg-css1-code">
        /* ⭕️ 標準サイズ(位置指定は不要) */<br>
        <span class="hdlg-css1-hl-blue">dialog.normal</span> {<br>
          <span class="hdlg-css1-hl-green">width: 90%;</span><br>
          <span class="hdlg-css1-hl-green">max-width: 500px;</span><br>
          border: none;<br>
        }<br><br>

        /* ⭕️ 全画面表示(フルスクリーン) */<br>
        <span class="hdlg-css1-hl-blue">dialog.fullscreen</span> {<br>
          <span class="hdlg-css1-hl-green">width: 100vw;</span><br>
          <span class="hdlg-css1-hl-green">height: 100vh;</span><br>
          <span class="hdlg-css1-hl-green">max-width: none;</span><br>
          <span class="hdlg-css1-hl-green">max-height: none;</span><br>
          <span class="hdlg-css1-hl-red">margin: 0;</span> /* ★ブラウザの自動マージンを消す */<br>
        }
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-css1-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-css1-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-css1-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 550px;
  border-radius: 4px;
}
.hdlg-css1-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-css1-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}
.hdlg-css1-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-css1-btn-sub {
  background-color: #212529;
  color: #fff;
  border: none;
  padding: 10px 15px;
  border-radius: 4px;
  cursor: pointer;
}
.hdlg-css1-btn-close {
  background-color: #e9ecef;
  border: 1px solid #ced4da;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 15px;
}

/* 1. 標準サイズのダイアログCSS */
.hdlg-css1-dialog-normal {
  width: 90%;
  max-width: 400px;
  border: none;
  border-radius: 8px;
  padding: 0;
  margin: auto;
  box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.hdlg-css1-inner {
  padding: 30px;
  text-align: center;
}

/* 2. 全画面サイズのダイアログCSS */
.hdlg-css1-dialog-full {
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  margin: 0; /* 必須 */
  border: none;
  padding: 0;
  border-radius: 0;
}
.hdlg-css1-inner-full {
  padding: 40px 20px;
  text-align: center;
  height: 100%;
  box-sizing: border-box;
  background-color: #fff;
}

.hdlg-css1-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}
.hdlg-css1-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-css1-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-css1-hl-red {
  color: #e06c75;
  font-weight: bold;
}
JavaScriptコード表示
setTimeout(() => {
  const dNormal = document.getElementById('css1-dialog-normal');
  const dFull = document.getElementById('css1-dialog-full');
  const bNormal = document.getElementById('css1-btn-normal');
  const bFull = document.getElementById('css1-btn-full');
  
  if(bNormal && dNormal) bNormal.onclick = () => dNormal.showModal();
  if(bFull && dFull) bFull.onclick = () => dFull.showModal();
  
  document.querySelectorAll('.js-css1-close').forEach(btn => {
    btn.onclick = (e) => e.target.closest('dialog').close();
  });
}, 100);

要素に対する幅/高さ・中央寄せについて詳しく知りたい人は以下から一読ください。

背景を暗くする・ぼかす設定

モーダルダイアログの視認性を高める上で、背後のコンテンツを暗くしたり、すりガラスのようにぼかしたりするデザインは人気があります。

背景のデザインを変更するには、ダイアログ要素に対して::backdrop疑似要素を使用します。

背景を半透明の黒にするだけでなく、CSSプロパティであるbackdrop-filter: blur();を組み合わせることで、iOS風のすりガラス効果(ブラー効果)を実装できます。

🎨 背景(backdrop)のカスタマイズ

背景の文字がぼやけるか確認してください

すりガラス効果

backdrop-filterプロパティを使用しています。

/* 💡 ダイアログそのもののデザイン */
dialog {
  border: none;
  border-radius: 8px;
}

/* 💡 ★背景(backdrop)のデザイン */
dialog::backdrop {
  /* 1. 背景を半透明の黒にする */
  background-color: rgba(0, 0, 0, 0.4);

  /* 2. 背景をすりガラスのようにぼかす(5px分) */
  backdrop-filter: blur(5px);
}
HTMLコード表示
<div class="hdlg-css2-wrapper">
  <div class="hdlg-css2-demo-area">
    <div class="hdlg-css2-box">
      <div class="hdlg-css2-label">🎨 背景(backdrop)のカスタマイズ</div>
      
      <div class="hdlg-css2-visual">
        <p style="font-size:16px; font-weight:bold; color:#0d6efd; margin-bottom:10px;">背景の文字がぼやけるか確認してください</p>
        <button id="css2-btn" class="hdlg-css2-btn-main">すりガラス背景で開く</button>
      </div>

      <dialog id="css2-dialog" class="hdlg-css2-dialog">
        <div class="hdlg-css2-inner">
          <div style="margin-top:0;">すりガラス効果</div>
          <p style="font-size:13px; color:#555;">backdrop-filterプロパティを使用しています。</p>
          <button id="css2-btn-close" class="hdlg-css2-btn-close">閉じる</button>
        </div>
      </dialog>

      <div class="hdlg-css2-code">
        /* 💡 ダイアログそのもののデザイン */<br>
        <span class="hdlg-css2-hl-blue">dialog</span> {<br>
          border: none;<br>
          border-radius: 8px;<br>
        }<br><br>

        /* 💡 ★背景(backdrop)のデザイン */<br>
        <span class="hdlg-css2-hl-blue">dialog::backdrop</span> {<br>
          <span class="hdlg-css2-hl-comment">/* 1. 背景を半透明の黒にする */</span><br>
          <span class="hdlg-css2-hl-green">background-color: rgba(0, 0, 0, 0.4);</span><br><br>
          <span class="hdlg-css2-hl-comment">/* 2. 背景をすりガラスのようにぼかす(5px分) */</span><br>
          <span class="hdlg-css2-hl-green">backdrop-filter: blur(5px);</span><br>
        }
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-css2-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
  /* ぼかし効果を分かりやすくするための背景模様 */
  background-image: radial-gradient(#adb5bd 1px, transparent 1px);
  background-size: 20px 20px;
}
.hdlg-css2-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-css2-box {
  background-color: rgba(255, 255, 255, 0.9);
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-css2-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-css2-visual {
  padding: 20px;
  margin-bottom: 20px;
  text-align: center;
}
.hdlg-css2-btn-main {
  background-color: #198754;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}
.hdlg-css2-btn-close {
  background-color: #e9ecef;
  border: 1px solid #ced4da;
  padding: 5px 15px;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 15px;
}

/* ダイアログとバックドロップのCSS */
.hdlg-css2-dialog {
  margin: auto;
  border: none;
  border-radius: 12px;
  padding: 0;
  box-shadow: 0 10px 25px rgba(0,0,0,0.2);
}
.hdlg-css2-inner {
  padding: 30px;
  text-align: center;
}

/* ★背景のカスタマイズ */
.hdlg-css2-dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(5px);
  /* Safari対応 */
  -webkit-backdrop-filter: blur(5px);
}

.hdlg-css2-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}
.hdlg-css2-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-css2-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-css2-hl-comment {
  color: #6c757d;
  font-style: italic;
}
JavaScriptコード表示
setTimeout(() => {
  const d = document.getElementById('css2-dialog');
  const o = document.getElementById('css2-btn');
  const c = document.getElementById('css2-btn-close');
  if(o && d) o.onclick = () => d.showModal();
  if(c && d) c.onclick = () => d.close();
}, 100);

開閉時のアニメーションの付け方

ダイアログがパッと一瞬で現れると、ユーザー体験(UX)としては唐突な印象を与えます。

ふわっと浮き出るようなアニメーションを追加することで、ユーザー体験を向上させます。

ダイアログが開く時のアニメーションを実装するには、transitionではなく、@keyframes(アニメーション定義)とdialog[open]属性セレクタを使用します。

(※なお「閉じる時」のアニメーションについては、CSS単体では実装できず、JavaScriptで閉じるタイミングを意図的に遅らせる複雑な処理が必要になるため、実務では「開く時のみフワッとさせる」のが手軽で効果的なベストプラクティスです。)

✨ 開く時のアニメーション
Fade In & Scale Up

@keyframesを使用して、滑らかに表示させています。

/* 💡 1. どんなアニメーションにするか定義する */
@keyframes fadeInScale {
  0% {
    opacity: 0;
    transform: scale(0.9) translateY(20px);
  }
  100% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

/* 💡 2. 開いた状態(open)になった時にアニメーションを実行 */
dialog[open] {
  animation: fadeInScale 0.3s ease-out forwards;
}

/* おまけ:背景(backdrop)もフワッと暗くする */
dialog[open]::backdrop {
  animation: backdropFade 0.3s ease-out forwards;
}
HTMLコード表示
<div class="hdlg-css3-wrapper">
  <div class="hdlg-css3-demo-area">
    <div class="hdlg-css3-box">
      <div class="hdlg-css3-label">✨ 開く時のアニメーション</div>
      
      <div class="hdlg-css3-visual">
        <button id="css3-btn" class="hdlg-css3-btn-main">アニメーション付きで開く</button>
      </div>

      <dialog id="css3-dialog" class="hdlg-css3-dialog">
        <div class="hdlg-css3-inner">
          <div style="margin-top:0;">Fade In & Scale Up</div>
          <p style="font-size:13px; color:#555;">@keyframesを使用して、滑らかに表示させています。</p>
          <button id="css3-btn-close" class="hdlg-css3-btn-close">閉じる</button>
        </div>
      </dialog>

      <div class="hdlg-css3-code">
        /* 💡 1. どんなアニメーションにするか定義する */<br>
        <span class="hdlg-css3-hl-blue">@keyframes fadeInScale</span> {<br>
          0% {<br>
            <span class="hdlg-css3-hl-green">opacity: 0;</span><br>
            <span class="hdlg-css3-hl-green">transform: scale(0.9) translateY(20px);</span><br>
          }<br>
          100% {<br>
            <span class="hdlg-css3-hl-green">opacity: 1;</span><br>
            <span class="hdlg-css3-hl-green">transform: scale(1) translateY(0);</span><br>
          }<br>
        }<br><br>

        /* 💡 2. 開いた状態(open)になった時にアニメーションを実行 */<br>
        <span class="hdlg-css3-hl-blue">dialog[open]</span> {<br>
          <span class="hdlg-css3-hl-red">animation: fadeInScale 0.3s ease-out forwards;</span><br>
        }<br><br>

        /* おまけ:背景(backdrop)もフワッと暗くする */<br>
        <span class="hdlg-css3-hl-blue">dialog[open]::backdrop</span> {<br>
          <span class="hdlg-css3-hl-red">animation: backdropFade 0.3s ease-out forwards;</span><br>
        }
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-css3-wrapper {
  background-color: #f8f9fa;
  padding: 20px;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}
.hdlg-css3-demo-area {
  display: flex;
  justify-content: center;
}
.hdlg-css3-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  border-radius: 4px;
}
.hdlg-css3-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}
.hdlg-css3-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}
.hdlg-css3-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}
.hdlg-css3-btn-close {
  background-color: #e9ecef;
  border: 1px solid #ced4da;
  padding: 5px 15px;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 15px;
}

/* ダイアログの初期設定 */
.hdlg-css3-dialog {
  margin: auto;
  border: none;
  border-radius: 12px;
  padding: 0;
  box-shadow: 0 10px 25px rgba(0,0,0,0.2);
}
.hdlg-css3-inner {
  padding: 30px;
  text-align: center;
}

/* ★ 1. ダイアログ本体のアニメーション定義 */
@keyframes hdlg-fade-in-scale {
  0% {
    opacity: 0;
    transform: scale(0.9) translateY(20px);
  }
  100% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

/* ★ 2. ダイアログ背景(backdrop)のアニメーション定義 */
@keyframes hdlg-backdrop-fade {
  0% {
    background-color: rgba(0, 0, 0, 0);
  }
  100% {
    background-color: rgba(0, 0, 0, 0.5);
  }
}

/* ★ 3. open属性がついた瞬間にアニメーションを発火 */
.hdlg-css3-dialog[open] {
  animation: hdlg-fade-in-scale 0.3s ease-out forwards;
}

.hdlg-css3-dialog[open]::backdrop {
  animation: hdlg-backdrop-fade 0.3s ease-out forwards;
}

.hdlg-css3-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}
.hdlg-css3-hl-green {
  color: #98c379;
  font-weight: bold;
}
.hdlg-css3-hl-blue {
  color: #61afef;
  font-weight: bold;
}
.hdlg-css3-hl-red {
  color: #e06c75;
  font-weight: bold;
}
JavaScriptコード表示
setTimeout(() => {
  const d = document.getElementById('css3-dialog');
  const o = document.getElementById('css3-btn');
  const c = document.getElementById('css3-btn-close');
  if(o && d) o.onclick = () => d.showModal();
  if(c && d) c.onclick = () => d.close();
}, 100);

様々な要素に対するCSSアニメーションの作り方を詳しく知りたい人は「【CSS】アニメーションの作り方:コピペで使えるおしゃれサンプル集」を一読ください。

アクセシビリティ・スクロール制御と高度な設定

<dialog>要素を実務のプロダクトに導入する際、画面の中央にポップアップを出すだけでは不十分です。

多様なユーザーが快適に操作できるためのアクセシビリティの担保、意図しない画面の動きを防ぐ属性の適切な設定が求められます。

ここでは、背景のスクロール問題の解決策、ブラウザ標準のフォーカス制御、最上位レイヤーの概念についてを解説します。

アクセシビリティ・スクロール制御と高度な設定
  • 背景のスクロールを無効化する
  • フォーカス制御とEscキーで閉じる設定
  • 最上位レイヤーとz-index

背景のスクロールを無効化する

モーダルダイアログを開いている最中に、マウスホイールを回したりスマホ画面をスワイプすると、ダイアログの「後ろ(背景)」にある画面がスクロールする現象は、UXを著しく損ないます。

背景のスクロールを防ぐには、JavaScriptのイベントキャンセルではなく、overflow: hidden;<body>要素に対して切り替えるのがよいです。

🚫 背景スクロールの無効化(prevent scroll)

↓ 下にスクロールできます ↓


スクロールエリア


ダイアログを開くと、このスクロールができなくなります。

スクロール停止中

後ろの画面はスクロールできません。

/* 💡 1. スクロールを止めるCSSクラスを用意 */
body.no-scroll {
  overflow: hidden !important;
}

/* 💡 2. JSでダイアログ開閉と同時にクラスを付け外しする */
openBtn.addEventListener(‘click’, () => {
  dialog.showModal();
  document.body.classList.add(‘no-scroll’);
});

dialog.addEventListener(‘close’, () => {
  document.body.classList.remove(‘no-scroll’);
});
HTMLコード表示
<div class="hdlg-adv1-wrapper">
  <div id="adv1-scroll-area" class="hdlg-adv1-demo-area">
    <div class="hdlg-adv1-box">
      <div class="hdlg-adv1-label">🚫 背景スクロールの無効化(prevent scroll)</div>
      
      <div class="hdlg-adv1-visual">
        <button id="adv1-open" class="hdlg-adv1-btn-main">ダイアログを開く</button>
        <p style="margin-top:20px; font-size:12px; color:#666;">
          ↓ 下にスクロールできます ↓<br><br><br>
          スクロールエリア<br><br><br>
          ダイアログを開くと、このスクロールができなくなります。
        </p>
      </div>

      <dialog id="adv1-dialog" class="hdlg-adv1-dialog">
        <div class="hdlg-adv1-inner">
          <div style="margin-top:0;">スクロール停止中</div>
          <p style="font-size:13px; color:#555;">後ろの画面はスクロールできません。</p>
          <button id="adv1-close" class="hdlg-adv1-btn-close">閉じる</button>
        </div>
      </dialog>

      <div class="hdlg-adv1-code">
        /* 💡 1. スクロールを止めるCSSクラスを用意 */<br>
        <span class="hdlg-adv1-hl-blue">body.no-scroll</span> {<br>
          <span class="hdlg-adv1-hl-red">overflow: hidden !important;</span><br>
        }<br><br>

        /* 💡 2. JSでダイアログ開閉と同時にクラスを付け外しする */<br>
        openBtn.addEventListener('click', () => {<br>
          dialog.showModal();<br>
          <span class="hdlg-adv1-hl-green">document.body.classList.add('no-scroll');</span><br>
        });<br><br>
        
        dialog.addEventListener('close', () => {<br>
          <span class="hdlg-adv1-hl-green">document.body.classList.remove('no-scroll');</span><br>
        });
      </div>
    </div>
  </div>
</div>
CSSコード表示
.hdlg-adv1-wrapper {
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 4px;
  font-family: sans-serif;
}

.hdlg-adv1-demo-area {
  padding: 20px;
  height: 400px;
  overflow-y: auto;
}

.hdlg-adv1-demo-area.no-scroll {
  overflow: hidden !important;
}

.hdlg-adv1-box {
  background-color: #ffffff;
  border: 2px dashed #adb5bd;
  padding: 25px;
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
  border-radius: 4px;
  min-height: 600px;
  box-sizing: border-box;
}

.hdlg-adv1-label {
  font-size: 15px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #333;
}

.hdlg-adv1-visual {
  background-color: #f1f3f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #dee2e6;
  text-align: center;
}

.hdlg-adv1-btn-main {
  background-color: #0d6efd;
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}

.hdlg-adv1-dialog {
  border: none;
  border-radius: 8px;
  padding: 0;
  box-shadow: 0 4px 15px rgba(0,0,0,0.2);
  margin: auto !important;
}

.hdlg-adv1-dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
}

.hdlg-adv1-inner {
  padding: 30px;
  text-align: center;
}

.hdlg-adv1-btn-close {
  background-color: #e9ecef;
  border: 1px solid #ced4da;
  padding: 5px 15px;
  border-radius: 4px;
  cursor: pointer;
}

.hdlg-adv1-code {
  background-color: #282c34;
  color: #abb2bf;
  padding: 15px;
  font-family: monospace;
  font-size: 13px;
  border-radius: 4px;
  line-height: 1.6;
  border-left: 4px solid #198754;
}

.hdlg-adv1-hl-green {
  color: #98c379;
  font-weight: bold;
}

.hdlg-adv1-hl-blue {
  color: #61afef;
  font-weight: bold;
}

.hdlg-adv1-hl-red {
  color: #e06c75;
  font-weight: bold;
}
JavaScriptコード表示
setTimeout(() => {
  const d = document.getElementById('adv1-dialog');
  const o = document.getElementById('adv1-open');
  const c = document.getElementById('adv1-close');
  const area = document.getElementById('adv1-scroll-area');
  
  if(o && d) {
    o.addEventListener('click', () => {
      d.showModal();
      area.classList.add('no-scroll');
    });
  }
  if(c && d) {
    c.addEventListener('click', () => {
      d.close();
    });
  }
  if(d) {
    d.addEventListener('close', () => {
      area.classList.remove('no-scroll');
    });
  }
}, 100);

overflowプロパティの使い方を詳しく知りたい人は「【html&css】overflowの使い方とhiddenやscrollの使い分け」を一読ください。

フォーカス制御とEscキーで閉じる設定

キーボード操作のみでブラウジングを行うユーザーにとって、ダイアログが開いた直後に「どこにフォーカス(選択状態)が当たっているか」は重要です。

<dialog>showModal()で開いた場合、フォーカストラップもESCキーで閉じる機能も、ブラウザが自動でやってくれます。

JSで自作する必要はありません。

ダイアログ内の「最初にフォーカスを当てたい要素(入力欄や閉じるボタン)」に対して、HTMLのautofocus属性を記述するだけです。

🎯 autofocusとフォーカストラップ
サイト内検索
  • 開いた瞬間、入力欄がアクティブになります。
  • Tabキーを押しても、外にフォーカスが逃げません。
  • ESCキーを押すとダイアログが閉じます。
  • <!– ❌ 間違い:JSで focus() や ESCキーの監視を書く –>

    <!– ⭕️ 大正解:HTMLに autofocus を書くだけ –>
    <dialog>
      <input type=”text” autofocus>
      <button>検索</button>
    </dialog>
    <!– ※フォーカスを逃さない処理も、ESCキーで閉じる処理も、
    すべてブラウザ(showModal)が自動で行います。 –>
    HTMLコード表示
    <div class="hdlg-adv2-wrapper">
      <div class="hdlg-adv2-demo-area">
        <div class="hdlg-adv2-box">
          <div class="hdlg-adv2-label">🎯 autofocusとフォーカストラップ</div>
          
          <div class="hdlg-adv2-visual">
            <button id="adv2-open" class="hdlg-adv2-btn-main">検索ダイアログを開く</button>
          </div>
    
          <dialog id="adv2-dialog" class="hdlg-adv2-dialog">
            <div class="hdlg-adv2-inner">
              <div style="margin-top:0;">サイト内検索</div>
              <input type="text" placeholder="キーワードを入力..." class="hdlg-adv2-input" autofocus>
              
              <div style="margin-top:15px; font-size:12px; color:#555; text-align:left;">
                <li>開いた瞬間、入力欄がアクティブになります。</li>
                <li>Tabキーを押しても、外にフォーカスが逃げません。</li>
                <li><strong>ESCキー</strong>を押すとダイアログが閉じます。</li>
              </div>
              
              <button id="adv2-close" class="hdlg-adv2-btn-close" style="margin-top:20px;">閉じる</button>
            </div>
          </dialog>
    
          <div class="hdlg-adv2-code">
            <!-- ❌ 間違い:JSで focus() や ESCキーの監視を書く --><br><br>
    
            <!-- ⭕️ 大正解:HTMLに autofocus を書くだけ --><br>
            <dialog><br>
              <input type="text" <span class="hdlg-adv2-hl-green">autofocus</span>><br>
              <button>検索</button><br>
            </dialog><br>
            <span class="hdlg-adv2-hl-comment"><!-- ※フォーカスを逃さない処理も、ESCキーで閉じる処理も、<br>
            すべてブラウザ(showModal)が自動で行います。 --></span>
          </div>
        </div>
      </div>
    </div>
    CSSコード表示
    .hdlg-adv2-wrapper {
      background-color: #f8f9fa;
      padding: 20px;
      border: 1px solid #dee2e6;
      border-radius: 4px;
      font-family: sans-serif;
    }
    .hdlg-adv2-demo-area {
      display: flex;
      justify-content: center;
    }
    .hdlg-adv2-box {
      background-color: #ffffff;
      border: 2px dashed #adb5bd;
      padding: 25px;
      width: 100%;
      max-width: 500px;
      border-radius: 4px;
    }
    .hdlg-adv2-label {
      font-size: 15px;
      font-weight: bold;
      margin-bottom: 20px;
      color: #333;
    }
    .hdlg-adv2-visual {
      background-color: #f1f3f5;
      padding: 20px;
      border-radius: 8px;
      margin-bottom: 20px;
      border: 1px solid #dee2e6;
      text-align: center;
    }
    .hdlg-adv2-btn-main {
      background-color: #0d6efd;
      color: #fff;
      border: none;
      padding: 10px 20px;
      border-radius: 4px;
      cursor: pointer;
      font-weight: bold;
    }
    .hdlg-adv2-dialog {
      margin: auto;
      border: none;
      border-radius: 8px;
      padding: 0;
      box-shadow: 0 4px 15px rgba(0,0,0,0.2);
    }
    .hdlg-adv2-dialog::backdrop {
      background-color: rgba(0, 0, 0, 0.5);
    }
    .hdlg-adv2-inner {
      padding: 30px;
      text-align: center;
      width: 250px;
    }
    .hdlg-adv2-input {
      width: 100%;
      padding: 10px;
      border: 1px solid #ced4da;
      border-radius: 4px;
      box-sizing: border-box;
    }
    /* autofocus時の見た目を分かりやすく */
    .hdlg-adv2-input:focus {
      outline: 2px solid #0d6efd;
      border-color: #0d6efd;
    }
    .hdlg-adv2-btn-close {
      background-color: #e9ecef;
      border: 1px solid #ced4da;
      padding: 5px 15px;
      border-radius: 4px;
      cursor: pointer;
    }
    .hdlg-adv2-code {
      background-color: #282c34;
      color: #abb2bf;
      padding: 15px;
      font-family: monospace;
      font-size: 13px;
      border-radius: 4px;
      line-height: 1.6;
      border-left: 4px solid #198754;
    }
    .hdlg-adv2-hl-green {
      color: #98c379;
      font-weight: bold;
    }
    .hdlg-adv2-hl-comment {
      color: #6c757d;
      font-style: italic;
    }
    JavaScriptコード表示
    setTimeout(() => {
      const d = document.getElementById('adv2-dialog');
      const o = document.getElementById('adv2-open');
      const c = document.getElementById('adv2-close');
      if(o && d) o.onclick = () => d.showModal();
      if(c && d) c.onclick = () => d.close();
    }, 100);

    最上位レイヤーとz-index

    Web制作で頭を悩ませる問題の一つが「z-indexの重なり順」です。

    「ヘッダー(z-index: 9999)の下にモーダルが潜り込んでしまう」と焦った経験を持つ開発者は多いでしょう。

    <dialog>showModal()で開いた場合、そもそもz-indexの概念自体が適用されません。

    ブラウザは通常のHTMLの階層とは切り離された「Top Layer(最上位レイヤー」という特別な最前面の空間にダイアログを描画します。

    そのため、背景のヘッダーがどれだけ巨大なz-indexを持っていようと、ダイアログは無条件で一番手前に表示されます。

    (※なお、ダイアログをマウスでドラッグして移動させる機能は標準では備わっていないため、必要な場合は別途JavaScriptのライブラリ等で実装する必要があります。)

    👑 最上位レイヤー(Top Layer)の威力
    z-index: 9999 のヘッダー

    z-indexが9999のヘッダーがあっても、
    dialogはそれを無視して必ず一番手前に出ます。

    私は Top Layer にいます

    z-indexの戦争から完全に解放されます。

    <!– ❌ 間違い:z-indexで無理やり手前に出そうとする –>
    <style>
      dialog {
        z-index: 999999;
      }
    </style>

    <!– ⭕️ 大正解:何も指定しなくてよい –>
    /* showModal() で開かれた要素は、
    ブラウザ独自の「Top Layer(最上位レイヤー)」に配置されるため、
    すべてのz-indexを無視して必ず最前面に表示されます。 */
    HTMLコード表示
    <div class="hdlg-adv3-wrapper">
      <div class="hdlg-adv3-demo-area">
        <div class="hdlg-adv3-box">
          <div class="hdlg-adv3-label">👑 最上位レイヤー(Top Layer)の威力</div>
          
          <div class="hdlg-adv3-visual">
            <div class="hdlg-adv3-fake-header">
              z-index: 9999 のヘッダー
            </div>
            
            <p style="margin-top:60px; font-size:12px; color:#555;">z-indexが9999のヘッダーがあっても、<br>dialogはそれを無視して必ず一番手前に出ます。</p>
            <button id="adv3-open" class="hdlg-adv3-btn-main" style="margin-top:10px;">ダイアログを開く</button>
          </div>
    
          <dialog id="adv3-dialog" class="hdlg-adv3-dialog">
            <div class="hdlg-adv3-inner">
              <div style="margin-top:0; color:#dc3545;">私は Top Layer にいます</div>
              <p style="font-size:13px;">z-indexの戦争から完全に解放されます。</p>
              <button id="adv3-close" class="hdlg-adv3-btn-close">閉じる</button>
            </div>
          </dialog>
    
          <div class="hdlg-adv3-code">
            <!-- ❌ 間違い:z-indexで無理やり手前に出そうとする --><br>
            <style><br>
              dialog {<br>
                <span class="hdlg-adv3-hl-red">z-index: 999999;</span><br>
              }<br>
            </style><br><br>
    
            <!-- ⭕️ 大正解:何も指定しなくてよい --><br>
            <span class="hdlg-adv3-hl-comment">/* showModal() で開かれた要素は、<br>
            ブラウザ独自の「Top Layer(最上位レイヤー)」に配置されるため、<br>
            すべてのz-indexを無視して必ず最前面に表示されます。 */</span>
          </div>
        </div>
      </div>
    </div>
    CSSコード表示
    .hdlg-adv3-wrapper {
      background-color: #f8f9fa;
      padding: 20px;
      border: 1px solid #dee2e6;
      border-radius: 4px;
      font-family: sans-serif;
    }
    .hdlg-adv3-demo-area {
      display: flex;
      justify-content: center;
    }
    .hdlg-adv3-box {
      background-color: #ffffff;
      border: 2px dashed #adb5bd;
      padding: 25px;
      width: 100%;
      max-width: 500px;
      border-radius: 4px;
    }
    .hdlg-adv3-label {
      font-size: 15px;
      font-weight: bold;
      margin-bottom: 20px;
      color: #333;
    }
    .hdlg-adv3-visual {
      background-color: #f1f3f5;
      padding: 20px;
      border-radius: 8px;
      margin-bottom: 20px;
      border: 1px solid #dee2e6;
      text-align: center;
      position: relative; /* 疑似ヘッダーの配置用 */
      overflow: hidden;
    }
    /* z-index: 9999 を持たせた強敵の疑似ヘッダー */
    .hdlg-adv3-fake-header {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      background-color: #212529;
      color: #fff;
      padding: 10px 0;
      font-weight: bold;
      font-size: 14px;
      z-index: 9999;
    }
    .hdlg-adv3-btn-main {
      background-color: #198754;
      color: #fff;
      border: none;
      padding: 10px 20px;
      border-radius: 4px;
      cursor: pointer;
      font-weight: bold;
    }
    /* ★z-indexは一切指定していません */
    .hdlg-adv3-dialog {
      margin: auto;
      border: none;
      border-radius: 8px;
      padding: 0;
      box-shadow: 0 4px 15px rgba(0,0,0,0.3);
    }
    .hdlg-adv3-dialog::backdrop {
      background-color: rgba(0, 0, 0, 0.6);
    }
    .hdlg-adv3-inner {
      padding: 40px 30px;
      text-align: center;
    }
    .hdlg-adv3-btn-close {
      background-color: #e9ecef;
      border: 1px solid #ced4da;
      padding: 5px 15px;
      border-radius: 4px;
      cursor: pointer;
    }
    .hdlg-adv3-code {
      background-color: #282c34;
      color: #abb2bf;
      padding: 15px;
      font-family: monospace;
      font-size: 13px;
      border-radius: 4px;
      line-height: 1.6;
      border-left: 4px solid #198754;
    }
    .hdlg-adv3-hl-red {
      color: #e06c75;
      font-weight: bold;
    }
    .hdlg-adv3-hl-comment {
      color: #6c757d;
      font-style: italic;
    }
    JavaScriptコード表示
    setTimeout(() => {
      const d = document.getElementById('adv3-dialog');
      const o = document.getElementById('adv3-open');
      const c = document.getElementById('adv3-close');
      if(o && d) o.onclick = () => d.showModal();
      if(c && d) c.onclick = () => d.close();
    }, 100);

    重なり順を指定するz-indexプロパティの使い方を詳しく知りたい人は「【html&css】z-indexとは?使い方と効かない時の対処」を一読ください。

    まとめ

    分かりやすいようにまとめを記載します。

    本記事のまとめ
    • <dialog>はブラウザネイティブのダイアログウィンドウを作成するHTML要素である。
    • showModal()メソッドで開くと背景操作がブロックされるモーダルになり、show()メソッドでは非モーダルになる。
    • open属性を付与すると初期表示できるが、常に非モーダルとして扱われる。
    • 内部に<form method="dialog">を設置すると、送信ボタン押下時にJavaScript不要でダイアログが閉じる。
    • CSSリセットによる位置ズレを防ぎ、中央配置するにはmargin: auto;(またはposition: fixed; inset: 0; margin: auto;)を指定する。
    • モーダル展開時の背景要素は::backdrop疑似要素で装飾できる。
    • 開閉時のアニメーションはtransitionではなく@keyframesdialog[open]属性セレクタを組み合わせて実装する。
    • ダイアログの終了検知及び戻り値の取得には、closeイベントとreturnValueプロパティを使用する。
    • 背景クリック時の終了処理は、クリックイベントの発生源(e.target === dialog)を判定して実装する。
    • 背景スクロールの停止機能は標準搭載されていないため、表示中にbody等へoverflow: hidden;を付与して制御する。
    • showModal()で開かれたダイアログは最上位レイヤーに描画されるため、z-indexによる階層調整は不要である。

    よくある質問(FAQ)

    HTMLの<dialog>タグとは何ですか?

    <dialog>は、ポップアップ画面やモーダルウィンドウを簡単に作成するHTML5の標準タグです。

    以前は複雑なJavaScriptや外部ライブラリが必要でしたが、ブラウザ標準の機能としてシンプルなコードでダイアログを実装できるようになりました。

    主に「警告」「確認画面」「入力フォーム」などに使われます。

    show() と showModal() の違いは何ですか?

    どちらもダイアログを開くJavaScriptメソッドですが、挙動が異なります。

    show()は「非モーダル」として開き、背景を暗くせず、背後にあるページのボタンなどもそのままクリックできます。

    一方、showModal()は「モーダル」として開き、背景の操作をブロックします。(標準で ::backdrop による背景暗転も適用されます。)

    一般的なポップアップを作りたい場合は、基本的にshowModal()を使用します。

    JavaScriptを使わずにダイアログを開閉することはできますか?

    はい、一部可能です。

    ページを開いた最初から表示させておきたい場合は、HTMLにopen属性(<dialog open>)をつけるだけで表示されます。(ただし非モーダルになります。)

    また、ダイアログを「閉じる」動作は、ダイアログ内に<form method="dialog">を配置し、送信ボタン(<button>)を押すことで、JavaScript不要で閉じる標準機能が備わっています。

    ダイアログの枠外をクリックして閉じるにはどうすればいいですか?

    <dialog>の標準機能には背景クリックで閉じる仕様がないため、JavaScriptでコードを書く必要があります。

    ダイアログに対してクリックイベントを設定し、クリックされた場所(e.target)がダイアログ要素だった場合」にclose()メソッドを実行する、という判定ロジックを追加するのが一般的な実装方法です。

    ダイアログが画面の中央に表示されず、上にずれてしまうのはなぜですか?

    最も多い原因は、サイト全体に適用している「リセットCSS」の影響です。

    ブラウザは本来margin: auto;を使ってダイアログを中央に配置しますが、* { margin: 0; }などのリセットCSSが打ち消してしまうため、上にずれてしまいます。

    解決するには、ダイアログのCSSに改めてmargin: auto !important;を指定し直すか、position: fixed; inset: 0;と組み合わせて強制的に中央へ固定してください。

    CONTACT

    サイト制作でお困りの人はお気軽にご連絡ください。
    どんなお悩み事も丁寧に返信させて頂きます。

    WordPress移行
    Webサイトを公開しよう!

    「どのサーバーを選べばいいか分からない…」そんな悩みを解決!
    WordPressデビューに最適なサーバーを徹底比較しました。

    この記事を書いた人

    sugiのアバター sugi Site operator

    【経歴】玉川大学工学部卒業→新卒SIer企業入社→2年半後に独立→プログラミングスクール運営/受託案件→フリーランスエンジニア&SEOコンサル→Python特化のコンテンツサイトJob Code&UIコピペサイトCode Stock運営中

    目次