css HTML `dialog`元素:独立于背景滚动内容

tjjdgumg  于 11个月前  发布在  其他
关注(0)|答案(5)|浏览(141)

我正在尝试使用dialog元素。
当对话框/模态关闭时,主体应该是可滚动的。
当对话框/模式打开时,如果它有很大的内容,对话框/模式应该是可滚动的。
然而,当对话框/模态打开时,我不希望滚动同时应用于对话框/模态 * 和 * 正文背景,这是默认情况下它所做的。
例如:https://output.jsbin.com/mutudop/3
当对话框/模式打开时,如何使滚动仅应用于对话框/模式内容?
注意:我只对使用原生dialog元素的解决方案感兴趣。

nzk0hqpo

nzk0hqpo1#

所以我也试了一下,得出了这个结论:

(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>

你可能已经注意到我添加了两行JS来隐藏/显示bodyoverflow,你可能需要它们,因为如果你想检查dialog是否打开,你不能用纯CSS来定位body
如果你想要它们,你可以**删除它们,它工作正常。但是,你会在右侧有两个滚动条。这是没有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");
    }
  });
})();

x

* {
  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>

的一个字符串
如果你需要任何解释,让我知道,但我相信代码应该是不言自明的。

niknxzdl

niknxzdl2#

这个答案考虑到了escape键。我将keydown事件侦听器添加到document.documentElement而不是实际的dialog元素。这是因为当dialog具有keydown事件侦听器时,它并不总是触发。例如,如果dialog打开,其中的一个按钮具有焦点,并且您按下escape键,keydown事件侦听器 * 将 * 触发。但让我们假设dialog中有一些文本,您突出显示文本,然后按escape键。在这种情况下,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>
ccrfmcuu

ccrfmcuu3#

2023/2024解决方案(仅限JavaScript / CSS)

现在可以使用CSS :has选择器来实现这一点。
添加以下CSS:

body:has(dialog[open]) {
  overflow: hidden;
}

字符串
如果您使用tailwindcss

<body className="[&:has(dialog[open])]:overflow-hidden">


上面的CSS将在dialog元素打开时从主体中删除滚动。
目前所有主流浏览器都支持:has选择器。请查看here的详细兼容性。

.long {
  height: 500vh;
  background-color: rebeccapurple;
}

body:has(dialog[open]) {
  overflow: hidden;
}
<div class="long">
  <button onclick="document.querySelector('dialog').showModal()">open dialog</button>
</div>

<dialog>
  Hello world!
</dialog>

的字符串

7eumitmz

7eumitmz4#

更新

我创建了另一个例子,如果你的主内容比你的主内容大,你可以在容器上将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");
    }
  });

})();

x

#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>

的一个字符串

bwntbbo3

bwntbbo35#

简单的解决方案是:一旦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");
    }
  });

})();

相关问题