HTML `dialog` element: scroll content independently of background

前端 未结 3 722
南旧
南旧 2021-01-21 18:33

I am trying to use the dialog element.

When the dialog/modal is closed, the body should be scrollable.

When the dialog/modal is open, if it has larg

相关标签:
3条回答
  • 2021-01-21 18:41

    Simple solution is : Once the mnodel is displayed make a one more DIV as overlay which covers full screen, in that place css { pointer-events:none} and model will be placed on top of that. user can not click on body content other than model data.

    I have created sample: 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");
        }
      });
    
    })();
    
    0 讨论(0)
  • 2021-01-21 18:50

    Update

    I created another example where your main content is not scrolled with your modal if it is larger than your main content. You can set position to fixed on your container to achieve this.

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

    Original answer

    You can set a max-height on your dialog and style the contents of your dialog accordingly. See example below.

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

    0 讨论(0)
  • 2021-01-21 19:00

    So I tried it as well and came up with this:

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

    You might have noticed that I added two lines of JS to hide/show the overflow of the body and you will probably need them as you can't target the body with pure CSS if you want to check if the dialog is opened or not.

    If you don't want them you can remove them and it just works fine. However, you will have two scroll bars on the right side. This is how it looks without the 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>

    If you need any explanation let me know but I believe the code should be self-explanatory.

    0 讨论(0)
提交回复
热议问题