網頁 Modal 視窗的現代寫法
| | | 1 | |
這篇說的 Modal 視窗 (Modal Dialog) 是指在現有網頁開啟一個較小視窗,強迫使用者必須完成閱讀或操作才能回到原網頁繼續操作,常用於警示、確認、開啟自訂選擇器之類的情境。打從 IE6 開始,設計網頁時我就很常使用 Modal 視窗,一路從 IE 時代的 showModalDialog、jQuery UI Dialog、Bootstrap Modal、Kendo UI Dialog、SweetAlert2,一直到四年前研發 showModalDialog 完整替代方案,也算得上經驗豐富,
而隨著開始用 Github Copilot 輔助開發,冷不防就看到 AI 露一手幾乎不用寫 JavaScript 的精巧 Modal 視窗寫法,讓我有自己還在媽媽十塊的羞愧感,這篇就來整理兩種 Low Code 的網頁 Modal 視窗寫法。
我用以下網頁示範,點日文等級旁的小藍 i 會彈出日本檢定的級數說明,以 Modal 視窗形式呈現,點紅 X 或遮罩空白處可關閉。

使用 CSS 動態切換
第一種做法是在網頁最後疊加一個內含 Modal 內容的 <div class="tips-modal">,設定 position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); 佔滿全頁(若有其他 position: absolute 元素再用 z-index 上移) 以半透明地蓋在原網頁上。一開始網頁設定 ‵display: none隱藏,點選小藍 i 時,為 .tips-modal 加上 .is-open 樣式,.is-open 會設定display: flex` 讓 div.tips-modal 顯現出來。要關閉則將 .is-open 樣式移除即可:
<body>
<table class="form">
<tr>
<td class="hdr">
日文等級
<i class="tip-button" onclick="document.querySelector('.tips-modal').classList.add('is-open')"></i>
</td>
<td>
<select>
<option value="N1">N1</option>
<option value="N2">N2</option>
<option value="N3">N3</option>
<option value="N4">N4</option>
<option value="N5">N5</option>
</select>
</td>
</tr>
</table>
<div class="tips-modal" onclick="if(event.target==this)this.classList.remove('is-open')">
<div class="content">
<table>
<thead>
<tr>
<th>級數</th>
<th>程度</th>
<th>
說明
<i class="close-button" onclick="document.querySelector('.tips-modal').classList.remove('is-open')"></i>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>N1</td>
<td>高階</td>
<td>可理解廣泛情境的日語,如閱讀新聞、評論、論說文等複雜文章,並能流利會話。</td>
</tr>
<!-- 省略 -->
</tbody>
</table>
</div>
</div>
</body>

HTML 原生 <dialog>
2022 起主流瀏覽器(Chrome 98+、Firefox 98+、Safari 15.4+)已全面支援 <dialog> 元素,讓我們能用更少的程式碼及 CSS 設定實現 Modal 視窗效果。
<dialog> 的寫法跟 CSS 切換式幾乎一模一樣,差別在可以少設定很多 CSS 樣式(遮罩樣式由 ::backgrop 偽元素控制),加上瀏覽器內建支持,可確保永遠在最上層(不需煩惱 z-index)、Tab 切換焦點操作限定在 dialog 內、支援 Escape 鍵關閉... 等,方便性更上一層樓。
<body>
<table class="form">
<tr>
<td class="hdr">
日文等級
<i class="tip-button" onclick="document.getElementById('tips-dialog').showModal()"></i>
</td>
<td>
<select>
<option value="N1">N1</option>
<option value="N2">N2</option>
<option value="N3">N3</option>
<option value="N4">N4</option>
<option value="N5">N5</option>
</select>
</td>
</tr>
</table>
<dialog id="tips-dialog" onclick="if(event.target===this)this.close()">
<div class="content">
<table>
<thead>
<tr>
<th>級數</th>
<th>程度</th>
<th>
說明
<i class="close-button" onclick="document.getElementById('tips-dialog').close()"></i>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>N1</td>
<td>高階</td>
<td>可理解廣泛情境的日語,如閱讀新聞、評論、論說文等複雜文章,並能流利會話。</td>
</tr>
<!-- 省略 -->
</tbody>
</table>
</div>
</dialog>
</body>

綜合比較
比較上述兩種做法,瀏覽器內建支援的 <dialog> 以 CSS 及 JavaScript 更簡潔、不受 z-index 影響、Tab 焦點受限、支援 Escape 鍵... 等優勢略勝一籌,CSS 的優勢在於可自訂動畫、佈局、樣式、可做滑入、淡入等過場效果,在大部分應用情境可優先考量使用 <dialog>。
Explores two low‑code ways to build modal dialogs: a CSS toggle overlay and the native HTML dialog element. Compares simplicity, accessibility, browser support, and customization, concluding dialog is usually the better modern choice with less JavaScript.
Comments
# by Proseidon
<dialog>方式下,在弹出的dialog中,原本选择文字之后,可以弹出翻译或者其它操作按钮的插件就不起作用了。CSS模式下正常。