HTML `dialog` 元素:独立于背景滚动内容
HTML `dialog` element: scroll content independently of background
我正在尝试使用 dialog
元素。
当 dialog/modal 关闭时,正文应该是可滚动的。
当dialog/modal打开时,如果内容较大,dialog/modal应该是可滚动的。
但是,当 dialog/modal 打开时,我不想滚动应用到 dialog/modal 和 正文背景,这是默认情况下它似乎在做什么。
示例:https://output.jsbin.com/mutudop/3.
当 dialog/modal 打开时,如何使滚动仅应用于 dialog/modal 内容?
注意:我只对使用原生 dialog
元素的解决方案感兴趣。
更新
我创建了另一个示例,其中如果您的主要内容大于您的主要内容,则您的主要内容不会随您的模式一起滚动。您可以在您的容器上将 position
设置为 fixed
以实现此目的。
(function() {
var openBtn = document.getElementById('open-dialog');
var myDialog = document.getElementById('my-dialog');
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
} else {
alert("Dialog API not supported by browser");
}
});
})();
#container {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
background: #ccc;
}
#my-dialog {
margin-top: 1rem;
margin-bottom: 3rem;
top: 3rem;
width: 50%;
overflow-y: auto;
}
#my-dialog__content {
display: flex;
flex-direction: column;
height: 200vh;
}
menu {
width: 100%;
padding: 0;
margin: 0 auto;
}
#cancel-button {
width: 100%
}
<div id="container">
<dialog id="my-dialog">
<div id="my-dialog__content">
<form method="dialog">
<menu>
<button id="cancel-button" value="cancel">Cancel</button>
</menu>
</form>
</div>
</dialog>
<menu>
<button id="open-dialog">Open Dialog</button>
</menu>
</div>
原回答
您可以在对话框中设置 max-height
并相应地设置对话框内容的样式。请参阅下面的示例。
(function() {
var openBtn = document.getElementById('open-dialog');
var myDialog = document.getElementById('my-dialog');
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
} else {
alert("Dialog API not supported by browser");
}
});
})();
#my-dialog {
width: 50%;
max-height: 50vh;
overflow-y: auto;
}
#my-dialog__content {
display: flex;
flex-direction: column;
height: 150vh;
}
menu {
width: 100%;
padding: 0;
margin: 0 auto;
}
#cancel-button {
width: 100%
}
<div id="container">
<dialog id="my-dialog">
<div id="my-dialog__content">
<form method="dialog">
<menu>
<button id="cancel-button" value="cancel">Cancel</button>
</menu>
</form>
</div>
</dialog>
<menu>
<button id="open-dialog">Open Dialog</button>
</menu>
</div>
简单的解决方案是:显示 mnodel 后,再制作一个 DIV 作为覆盖全屏的覆盖层,在那个地方 css { pointer-events:none } 和模型将被放置在上面。用户不能点击模型数据以外的正文内容。
我已经创建了样本:http://jsfiddle.net/z3sgvnox/
<body id="content-body">
<div id="container">
<dialog id="my-dialog">
<div id="my-dialog__content">
<form method="dialog">
<menu>
<button id="cancel-button" value="cancel">Cancel</button>
</menu>
</form>
</div>
</dialog>
<menu>
<button id="open-dialog">Open Dialog</button>
</menu>
</div>
</body>
CSS
#container {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
background: #ccc;
}
#my-dialog {
margin-top: 1rem;
margin-bottom: 3rem;
width: 50%;
overflow-y: auto;
max-height: 80%;
}
.hideScroll{
overflow:hidden;
pointer-events:none;
}
#my-dialog__content {
display: flex;
flex-direction: column;
height: 200vh;
}
menu {
width: 100%;
padding: 0;
margin: 0 auto;
}
#cancel-button {
width: 100%
}
JS:
(function() {
var openBtn = document.getElementById('open-dialog');
var myDialog = document.getElementById('my-dialog');
var bodyData = document.getElementById('content-body');
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
bodyData.classList.add("hideScroll");
} else {
alert("Dialog API not supported by browser");
}
});
})();
所以我也试了一下,想出了这个:
(function() {
var openBtn = document.querySelector("button#open");
var myDialog = document.querySelector("dialog");
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
document.querySelector("body").classList.add("overflow-hidden");
} else {
alert("Dialog API not supported by browser");
}
});
})();
* {
box-sizing: border-box;
}
.wrapper {
height: 10000px;
}
dialog {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
z-index: 100;
background: transparent;
overflow-y: auto;
}
dialog>div {
width: 50%;
height: 500px;
background: white;
border: 3px solid black;
margin: 0 auto;
margin-top: 50px;
}
.overflow-hidden {
overflow: hidden;
}
<div class="wrapper">
<dialog>
<div>
<form method="dialog">
<button onclick='document.body.classList.remove("overflow-hidden");' value="cancel">Cancel</button>
</form>
</div>
</dialog>
<button id="open">Open Dialog</button>
<h4>You can scroll the body now but not when the dialog is opened.</h4>
</div>
您可能已经注意到我在 hide/show 和 body
的 overflow
中添加了两行 JS,您可能需要它们,因为您无法定位 body
与纯 CSS 如果你想检查 dialog
是否打开。
如果您不想要它们,您可以删除它们并且效果很好。但是,您将在右侧有两个滚动条。这是没有 JS 的样子:
(function() {
var openBtn = document.querySelector("button#open");
var myDialog = document.querySelector("dialog");
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
} else {
alert("Dialog API not supported by browser");
}
});
})();
* {
box-sizing: border-box;
}
.wrapper {
height: 10000px;
}
dialog {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
z-index: 100;
background: transparent;
overflow-y: auto;
}
dialog>div {
width: 50%;
height: 500px;
background: white;
border: 3px solid black;
margin: 0 auto;
margin-top: 50px;
}
.overflow-hidden {
overflow: hidden;
}
<div class="wrapper">
<dialog>
<div>
<form method="dialog">
<button value="cancel">Cancel</button>
</form>
</div>
</dialog>
<button id="open">Open Dialog</button>
</div>
如果您需要任何解释,请告诉我,但我认为代码应该是 self-explanatory。
这个答案考虑了转义键。我将 keydown
事件侦听器添加到 document.documentElement
而不是实际的 dialog
元素。这是因为当 dialog
有一个 keydown
事件侦听器时,它并不总是触发。例如,如果 dialog
打开并且其中的按钮具有焦点并且您按下转义键,keydown
事件侦听器 将触发 。但是让我们假设 dialog
中有一些文本,您突出显示该文本,然后按转义键。在这种情况下,keydown
事件侦听器将不会 触发。
const activeModals = [];
function openModal(dialogSelector) {
const dialog = document.querySelector(dialogSelector);
dialog.showModal();
activeModals.push(dialog);
document.body.classList.add('overflow-hidden');
}
function closeActiveModal() {
const activeModal = activeModals.pop();
activeModal.close();
if (activeModals.length === 0) {
document.body.classList.remove('overflow-hidden');
}
}
document.documentElement.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && activeModals.length) {
e.preventDefault();
closeActiveModal();
}
});
document.querySelectorAll('[data-toggle="modal"]').forEach((button) => {
button.addEventListener('click', () => {
openModal(button.getAttribute('data-target'));
});
});
document.querySelectorAll('[data-dismiss="modal"]').forEach((button) => {
button.addEventListener('click', closeActiveModal);
});
let fillerHtml = '';
for (let i = 1; i <= 100; i++) {
fillerHtml += `<p>${i}</p>`;
}
document.querySelectorAll('.filler').forEach((div) => {
div.innerHTML = fillerHtml;
});
.overflow-hidden {
overflow: hidden;
}
p {
font-size: 20px;
}
<button data-toggle="modal" data-target="#dialog1">Open Dialog 1</button>
<dialog id="dialog1">
<h1>Dialog 1</h1>
<button data-dismiss="modal">Close Dialog 1</button>
<button data-toggle="modal" data-target="#dialog2">Open Dialog 2</button>
<div class="filler"></div>
</dialog>
<dialog id="dialog2">
<h1>Dialog 2</h1>
<button data-dismiss="modal">Close Dialog 2</button>
</dialog>
<div class="filler"></div>
我正在尝试使用 dialog
元素。
当 dialog/modal 关闭时,正文应该是可滚动的。
当dialog/modal打开时,如果内容较大,dialog/modal应该是可滚动的。
但是,当 dialog/modal 打开时,我不想滚动应用到 dialog/modal 和 正文背景,这是默认情况下它似乎在做什么。
示例:https://output.jsbin.com/mutudop/3.
当 dialog/modal 打开时,如何使滚动仅应用于 dialog/modal 内容?
注意:我只对使用原生 dialog
元素的解决方案感兴趣。
更新
我创建了另一个示例,其中如果您的主要内容大于您的主要内容,则您的主要内容不会随您的模式一起滚动。您可以在您的容器上将 position
设置为 fixed
以实现此目的。
(function() {
var openBtn = document.getElementById('open-dialog');
var myDialog = document.getElementById('my-dialog');
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
} else {
alert("Dialog API not supported by browser");
}
});
})();
#container {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
background: #ccc;
}
#my-dialog {
margin-top: 1rem;
margin-bottom: 3rem;
top: 3rem;
width: 50%;
overflow-y: auto;
}
#my-dialog__content {
display: flex;
flex-direction: column;
height: 200vh;
}
menu {
width: 100%;
padding: 0;
margin: 0 auto;
}
#cancel-button {
width: 100%
}
<div id="container">
<dialog id="my-dialog">
<div id="my-dialog__content">
<form method="dialog">
<menu>
<button id="cancel-button" value="cancel">Cancel</button>
</menu>
</form>
</div>
</dialog>
<menu>
<button id="open-dialog">Open Dialog</button>
</menu>
</div>
原回答
您可以在对话框中设置 max-height
并相应地设置对话框内容的样式。请参阅下面的示例。
(function() {
var openBtn = document.getElementById('open-dialog');
var myDialog = document.getElementById('my-dialog');
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
} else {
alert("Dialog API not supported by browser");
}
});
})();
#my-dialog {
width: 50%;
max-height: 50vh;
overflow-y: auto;
}
#my-dialog__content {
display: flex;
flex-direction: column;
height: 150vh;
}
menu {
width: 100%;
padding: 0;
margin: 0 auto;
}
#cancel-button {
width: 100%
}
<div id="container">
<dialog id="my-dialog">
<div id="my-dialog__content">
<form method="dialog">
<menu>
<button id="cancel-button" value="cancel">Cancel</button>
</menu>
</form>
</div>
</dialog>
<menu>
<button id="open-dialog">Open Dialog</button>
</menu>
</div>
简单的解决方案是:显示 mnodel 后,再制作一个 DIV 作为覆盖全屏的覆盖层,在那个地方 css { pointer-events:none } 和模型将被放置在上面。用户不能点击模型数据以外的正文内容。
我已经创建了样本:http://jsfiddle.net/z3sgvnox/
<body id="content-body">
<div id="container">
<dialog id="my-dialog">
<div id="my-dialog__content">
<form method="dialog">
<menu>
<button id="cancel-button" value="cancel">Cancel</button>
</menu>
</form>
</div>
</dialog>
<menu>
<button id="open-dialog">Open Dialog</button>
</menu>
</div>
</body>
CSS
#container {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
background: #ccc;
}
#my-dialog {
margin-top: 1rem;
margin-bottom: 3rem;
width: 50%;
overflow-y: auto;
max-height: 80%;
}
.hideScroll{
overflow:hidden;
pointer-events:none;
}
#my-dialog__content {
display: flex;
flex-direction: column;
height: 200vh;
}
menu {
width: 100%;
padding: 0;
margin: 0 auto;
}
#cancel-button {
width: 100%
}
JS:
(function() {
var openBtn = document.getElementById('open-dialog');
var myDialog = document.getElementById('my-dialog');
var bodyData = document.getElementById('content-body');
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
bodyData.classList.add("hideScroll");
} else {
alert("Dialog API not supported by browser");
}
});
})();
所以我也试了一下,想出了这个:
(function() {
var openBtn = document.querySelector("button#open");
var myDialog = document.querySelector("dialog");
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
document.querySelector("body").classList.add("overflow-hidden");
} else {
alert("Dialog API not supported by browser");
}
});
})();
* {
box-sizing: border-box;
}
.wrapper {
height: 10000px;
}
dialog {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
z-index: 100;
background: transparent;
overflow-y: auto;
}
dialog>div {
width: 50%;
height: 500px;
background: white;
border: 3px solid black;
margin: 0 auto;
margin-top: 50px;
}
.overflow-hidden {
overflow: hidden;
}
<div class="wrapper">
<dialog>
<div>
<form method="dialog">
<button onclick='document.body.classList.remove("overflow-hidden");' value="cancel">Cancel</button>
</form>
</div>
</dialog>
<button id="open">Open Dialog</button>
<h4>You can scroll the body now but not when the dialog is opened.</h4>
</div>
您可能已经注意到我在 hide/show 和 body
的 overflow
中添加了两行 JS,您可能需要它们,因为您无法定位 body
与纯 CSS 如果你想检查 dialog
是否打开。
如果您不想要它们,您可以删除它们并且效果很好。但是,您将在右侧有两个滚动条。这是没有 JS 的样子:
(function() {
var openBtn = document.querySelector("button#open");
var myDialog = document.querySelector("dialog");
openBtn.addEventListener('click', function() {
if (typeof myDialog.showModal === "function") {
myDialog.showModal();
} else {
alert("Dialog API not supported by browser");
}
});
})();
* {
box-sizing: border-box;
}
.wrapper {
height: 10000px;
}
dialog {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
z-index: 100;
background: transparent;
overflow-y: auto;
}
dialog>div {
width: 50%;
height: 500px;
background: white;
border: 3px solid black;
margin: 0 auto;
margin-top: 50px;
}
.overflow-hidden {
overflow: hidden;
}
<div class="wrapper">
<dialog>
<div>
<form method="dialog">
<button value="cancel">Cancel</button>
</form>
</div>
</dialog>
<button id="open">Open Dialog</button>
</div>
如果您需要任何解释,请告诉我,但我认为代码应该是 self-explanatory。
这个答案考虑了转义键。我将 keydown
事件侦听器添加到 document.documentElement
而不是实际的 dialog
元素。这是因为当 dialog
有一个 keydown
事件侦听器时,它并不总是触发。例如,如果 dialog
打开并且其中的按钮具有焦点并且您按下转义键,keydown
事件侦听器 将触发 。但是让我们假设 dialog
中有一些文本,您突出显示该文本,然后按转义键。在这种情况下,keydown
事件侦听器将不会 触发。
const activeModals = [];
function openModal(dialogSelector) {
const dialog = document.querySelector(dialogSelector);
dialog.showModal();
activeModals.push(dialog);
document.body.classList.add('overflow-hidden');
}
function closeActiveModal() {
const activeModal = activeModals.pop();
activeModal.close();
if (activeModals.length === 0) {
document.body.classList.remove('overflow-hidden');
}
}
document.documentElement.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && activeModals.length) {
e.preventDefault();
closeActiveModal();
}
});
document.querySelectorAll('[data-toggle="modal"]').forEach((button) => {
button.addEventListener('click', () => {
openModal(button.getAttribute('data-target'));
});
});
document.querySelectorAll('[data-dismiss="modal"]').forEach((button) => {
button.addEventListener('click', closeActiveModal);
});
let fillerHtml = '';
for (let i = 1; i <= 100; i++) {
fillerHtml += `<p>${i}</p>`;
}
document.querySelectorAll('.filler').forEach((div) => {
div.innerHTML = fillerHtml;
});
.overflow-hidden {
overflow: hidden;
}
p {
font-size: 20px;
}
<button data-toggle="modal" data-target="#dialog1">Open Dialog 1</button>
<dialog id="dialog1">
<h1>Dialog 1</h1>
<button data-dismiss="modal">Close Dialog 1</button>
<button data-toggle="modal" data-target="#dialog2">Open Dialog 2</button>
<div class="filler"></div>
</dialog>
<dialog id="dialog2">
<h1>Dialog 2</h1>
<button data-dismiss="modal">Close Dialog 2</button>
</dialog>
<div class="filler"></div>