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配置报错,不 ...
随机推荐
- Service Mesh Summit 回顾 | 轻舟服务网格的无侵入增强 Istio 经验
在云原生社区近日主办的 Service Mesh Summit 2022 服务网格峰会上,网易数帆云原生技术专家方志恒分享了轻舟服务网格无侵入增强 Istio 的经验,本文据此次分享整理,介绍了对无侵 ...
- git fetch origin
可以运行 git fetch origin 来同步远程服务器上的数据到本地.该命令首先找到 origin 是哪个服务器(本例为 git.ourcompany.com),从上面获取你尚未拥有的数据,更新 ...
- oeasy教您玩转vim - 51 - # 读写文件
读写文件 回忆上节课内容 命令行的光标控制 方向键️️️️️可以控制左右移动 shift+️️️️️按照word左右移动光标 ctrl+b 到开头begin ctrl+e 到结尾end ctrl+w ...
- App如何利用推送消息有效实现拉新促活?
对于大多数App来说,如何快速建立与用户的联系.提高用户活跃度.提升用户转化率,是产品运营过程中十分关心的问题,在常见的运营手段中,Push推送消息以其高性价比成为首选策略.但在实际运营过程中,推送消 ...
- 《Programming from the Ground Up》阅读笔记:p75-p87
<Programming from the Ground Up>学习第4天,p75-p87总结,总计13页. 一.技术总结 1.persistent data p75, Data whic ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-58 - 文件下载
1.简介 前边几篇文章讲解完如何上传文件,既然有上传,那么就可能会有下载文件.因此宏哥就接着讲解和分享一下:自动化测试下载文件.可能有的小伙伴或者童鞋们会觉得这不是很简单吗,还用你介绍和讲解啊,不说就 ...
- Python将本地文件上传到服务器
1.首先本地有一个文件"E:\Double\python\dataCheck\html_detail\20221206140345_activeBug.html",我需要上传到服务 ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-60 - 判断元素是否显示 - 下篇
1.简介 有些页面元素的生命周期如同流星一闪,昙花一现.我们也不知道这个元素在没在页面中出现过,为了捕获这一美好瞬间,让其成为永恒.我们就来判断元素是否显示出现过. 在操作元素之前,可以先判断元素的状 ...
- 【BatchProgram】工作用的小工具 - 自动访问常用页面
需求: 我需要打开很多页面,但是忘了收藏的话,每次都要重新去找一遍打开 页面很多,不是一两个了,为什么这么多?因为开发情况就是这样啊: 正式生产一个页面,UAT测试一个页面,本地调试一个页面 每日工作 ...
- 【Spring】09 后续的学习补充 vol3
原生JDBC事务: package dao; import cn.dzz.util.DruidUtil; import org.apache.commons.dbutils.QueryRunner; ...