CSS & JS Effect – Dialog Modal
效果

参考:
Youtube – Create a Simple Popup Modal
Youtube – Create a Modal (Popup) with HTML/CSS and JavaScript
重点
1. modal 就是一个 position: fixed 的大 overlay 黑影, 同时里面有居中的 content box.
2. modal 原本是 hide 起来的, 点击后 show 就可以了.
HTML
<body>
<button id="js-open-modal-btn" class="open-modal-btn">Open Modal</button>
<div id="js-modal" class="modal">
<div class="content">
<div class="header">
<h1>You are The Winner!</h1>
<button id="js-close-modal-btn" class="close-modal-btn"><i class="fa-solid fa-xmark"></i></button>
</div>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Repellat id, rem veniam ratione modi laboriosam consectetur vitae illum perspiciatis recusandae!</p>
</div>
</div>
</body>
modal 负责 backdrop 黑影
content 则是中间白色的内容区域
CSS Style

.open-modal-btn{
margin-top: 17rem;
margin-inline: auto;
display: block;
}
.modal {
visibility: hidden; // show / hide control
position: fixed; // 定位
inset: 0; // full viewport
background-color: rgb(0 0 0 / 0.2); // backdrop color
// 居中 content
display: flex;
justify-content: center;
align-items: center;
.content {
padding: 2rem 3rem;
max-width: 1024px;
background-color: white; // 因为 modal 是透明黑, 所以这里要 set 回白色
box-shadow: 0 2px 4px rgb(0 0 0 / 0.2); // 影子
.header{
display: flex;
justify-content: space-between;
align-items: center;
font-size: 3rem;
.close-modal-btn {
background-color: white;
font-size: inherit;
color: black;
border-width: 0;
cursor: pointer;
}
}
p{
margin-top: 2rem;
font-size: 2rem;
}
}
&.show {
visibility: initial; // clear visibility to show
}
}
看注释的地方解释就可以了, 其它是点缀而已
JavaScript
const modal = document.querySelector<HTMLElement>('#js-modal')!;
const openModalBtn = document.querySelector<HTMLButtonElement>('#js-open-modal-btn')!;
const closeModalBtn = document.querySelector<HTMLButtonElement>('#js-close-modal-btn')!;
openModalBtn.addEventListener('click', () => {
modal.classList.add('show');
});
closeModalBtn.addEventListener('click', () => {
modal.classList.remove('show');
});
只是简单的点击 add class 而已
Body Scroll IOS Safari Problem
modal 开启后, 通常体验不允许 body scroll. 一般的做法是给 body overflow: hidden
但是这个在 Safari 有 bug. 目前 status 是说已经 fixed 了, 但是我没用最新的 safari 测试, 所以不确定.
解决方法是让 body position fixed, 然后修改它的 top 到当前的 scroll top.
下面是我封装的方法
// note: 来龙去脉
// safari 没有办法通过 overflow hide 去阻止 body scroll
// 所以只能把 body 定位变成没有 scroll
// 这个 safari 问题已经很多年的了
// tesla, angular, stackoverflow 也是用这个方案去破
// bootstrap 倒没有处理这个, 比较 noob
// refer:
// https://bugs.webkit.org/show_bug.cgi?id=153852
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block const showedModals: string[] = []; export function toggleModal(modalName: string): void {
showedModals.includes(modalName) ? closeModal(modalName) : openModal(modalName);
} export function openModal(modalName: string): void {
if (showedModals.length === 0) {
const currentScrollTop = (document.scrollingElement ?? document.documentElement).scrollTop;
document.body.style.position = 'fixed';
document.body.style.width = '100%';
document.body.style.top = `-${currentScrollTop}px`;
}
showedModals.push(modalName);
} export function closeModal(modalName: string): void {
if (!showedModals.includes(modalName)) {
throw new Error(`Showed modals doesn't contains modal name: ${modalName}`);
}
if (showedModals.length === 1) {
const recoveryScrollTop = Math.abs(parseFloat(document.body.style.top));
document.body.style.removeProperty('position');
document.body.style.removeProperty('width');
document.body.style.removeProperty('top');
(document.scrollingElement ?? document.documentElement).scrollTop = recoveryScrollTop;
}
const indexOf = showedModals.indexOf(modalName);
showedModals.splice(indexOf, 1);
}
Mobile Back Button Close Dialog
大家习惯按手机的 back button 来试图关闭 Modal,
其实这是一个不正确的操作. 因为 back 会直接跳去上一页而不是关闭 Modal.
为了防止这样的错误体验. 我们可以做一点手脚.
step 1: 在打开 Modal的同时 history.push 放入 query param ?modal="show" (这样之后就可以 back 了)
step 2: 把关闭的操作 改成 history.back (统一关闭的方式)
step 3: 监听 onpopstate, 一旦发生就关闭 Modal.
step 4: 如果用户 refresh 那我们需要在 page load 的时候把 ?modal=show 用 history.replace 移除掉
以上的方法思路只是 for 简单场景的. 如果有多层 modal 或者更复杂的情况就 cover 不了了.
JS 代码:

const modal = document.querySelector<HTMLElement>('#js-modal')!;
const openModalBtn = document.querySelector<HTMLButtonElement>('#js-open-modal-btn')!;
const closeModalBtn = document.querySelector<HTMLButtonElement>('#js-close-modal-btn')!;
// 处理 page load
const { pathname, search, hash } = location;
const queryParams = new URLSearchParams(search);
if (queryParams.has('whatsAppDialog')) {
queryParams.delete('whatsAppDialog');
const newSearch = queryParams.toString() !== '' ? `?${queryParams.toString()}` : '';
history.replaceState(null, '', `${pathname}${newSearch}${hash}`);
}
openModalBtn.addEventListener('click', () => {
modal.classList.add('show');
// pushState
const { pathname, search, hash } = location;
const params = new URLSearchParams(search);
params.set('whatsAppDialog', 'open');
history.pushState(null, '', `${pathname}?${params.toString()}${hash}`);
// listen to 'back button'
window.addEventListener(
'popstate',
() => {
modal.classList.remove('show');
},
{ once: true }
);
});
closeModalBtn.addEventListener('click', () => {
history.back(); // back
});
另外, 未来或许可以用 Navigation API 实现, 可能会更方便. 以后才研究. 毕竟现在许多 browser 还不支持.

其它没有提到的
1. backdrop click, Keyboard Esc 关闭.
2. show 的 animation, backdrop fadein, content scale in
3. z-index 问题. 要确保 z-index 够高最好是把 modal 放到 body 最下方 (Angular Material 就这么做的)
但放出去后要注意 CSS Style 哦. element 结构在外面了就不可以 depend on ancestor 了.
CSS & JS Effect – Dialog Modal的更多相关文章
- [转]jQuery UI Dialog Modal Popup Yes No Confirm example in ASP.Net
本文转自:http://www.aspsnippets.com/Articles/jQuery-UI-Dialog-Modal-Popup-Yes-No-Confirm-example-in-ASPN ...
- HTML/CSS/JS编码规范
最近整理了一份HTML/CSS/JS编码规范,供大家参考.目录:一.HTML编码规范二.CSS编码规范三.JS编码规范 一.HTML编码规范 1. img标签要写alt属性 根据W3C标准,img标签 ...
- CSS & JS 制作滚动幻灯片
==================纯CSS方式==================== <!DOCTYPE html> <html> <head> <met ...
- 【转】Maven Jetty 插件的问题(css/js等目录死锁)的解决
Maven Jetty 插件的问题(css/js等目录死锁,不能自动刷新)的解决: 1. 打开下面的目录:C:\Users\用户名\.m2\repository\org\eclipse\jetty ...
- Css Js Loader For Zencart
Css Js Loader 描述:这个插件很早就出来了,可能知道人非常少 这个插件的功能是整合所有的网站的CSS和JS内容到一个文件里边. 因为CSS和JS文件到了一个文件,加快了程序的运行 在配合其 ...
- 购物车数字加减按钮HTML+CSS+JS(有需要嫌麻烦的小伙伴拿走不谢)
之前在写详情页的时候,如下图 因为自己嫌麻烦,就去看其他网站是怎么写的,想直接拿来用,后来看来看去觉得写得很麻烦,于是最后还是决定自己写,附上HTML+CSS+JS代码,一条龙一站式贴心服务2333 ...
- vs合并压缩css,js插件——Bundler & Minifier
之前做了一个大转盘的抽奖活动,因为比较火,部分用户反馈看不到页面的情况,我怀疑js加载请求过慢导致,所以今天针对之前的一个页面进行调试优化. 首先想到的是对页面的js和css进行压缩优化,百度了下vs ...
- nginx资源定向 css js路径问题
今天玩玩项目,学学nginx发现还不错,速度还可以,但是CSS JS确无法使用,原来Iginx配置时需要对不同类型的文件配置规则,真是很郁闷,不过想想也还是很有道理.闲暇之际,把配置贴上来.#user ...
- IIS7的集成模式下如何让自定义的HttpModule不处理静态文件(.html .css .js .jpeg等)请求
今天将开发好的ASP.NET站点部署到客户的服务器上后,发现了一个非常头疼的问题,那么就是IIS7的应用程序池是集成模式的话,ASP.NET项目中自定义的HttpModule会处理静态文件(.html ...
- 网站加载css/js/img等静态文件失败
网站加载css/js/img等静态文件失败,报网站http服务器内部500错误.而服务器中静态文件存在且权限正常. 从浏览器中直接访问文件,出来乱码.这种问题原因在于iis中该网站mime配置报错,不 ...
随机推荐
- js 异步 任务 题目解析(chatgpt bug了?)
最近遇到一道题如下,求输出结果 感觉还是蛮有意思的,找chatgpt做了一下 我是题 async function async1(){ console.log('1'); await async2() ...
- vue 理解yarn start 和yarn dev的区别
yarn dev,当文件变动后,会自动重启. yanr start不会自动重启 nodemon会监听文件变动,跟yarn dev和yarn start无关.
- oeasy教您玩转vim - 51 - # 读写文件
读写文件 回忆上节课内容 命令行的光标控制 方向键️️️️️可以控制左右移动 shift+️️️️️按照word左右移动光标 ctrl+b 到开头begin ctrl+e 到结尾end ctrl+w ...
- Web开发中【密码加密】详解
作为一名Web开发人员,我们经常需要与用户的帐号系统打交道,而这其中最大的挑战就是如何保护用户的密码.经常会看到用户账户数据库频繁被黑,所以我们必须采取一些措施来保护用户密码,以免导致不必要的数据泄露 ...
- python的Faker使用
import json from faker import Faker from faker_demo.CustomFaker import CustomProvider myfaker = Fake ...
- 【Linux】快速文件交互 lrzsz
首先需要安装依赖: yum install -y lrzsz 没有此依赖,Linux提示找不到命令: [root@localhost ~]# rz -bash: rz: 未找到命令 [root@loc ...
- “Vanilla” 在计算机科学和技术领域中的专业翻译
"Vanilla" 在计算机科学和技术领域中通常指的是某个系统或软件的"原始"或"基础"版本,即没有任何修改.扩展或定制的版本.它可以翻译为 ...
- git警告信息:Encountered 1 file(s) that may not have been copied correctly on Windows: —— See: `git lfs help smudge` for more details.
git报警信息: 官方讨论的帖子: https://github.com/git-lfs/git-lfs/issues/2434 说下个人的理解: 在git管理中,对于大文件(一般为压缩后的二进制文件 ...
- spring之事务详解
1.背景 该博客要解决的重要问题如下: spring的3种安全性问题,4种事务特性,5种隔离级别,7种传播行为 spring的3种安全性问题,4种事务特性,5种隔离级别,7种传播行为 spring事务 ...
- css手撕奥运五环
巴黎奥运会正如火如荼地进行,本文来使用 CSS 来画一个奥运五环.奥运五环是相互连接的,因此在视觉上会产生重叠效果,这也是实现五环最有挑战性的部分.接下来,将利用 CSS 的伪元素,巧妙地实现环环相扣 ...