Set top of a div in relation to the screen

0

I have a div that appears when I touch an open button (similar to a modal), this button appears n times along the page, my problem is that if it has been scrolled down and clicked on the button to open, the div appears at the top of the page and the user must scroll up to see it, how could you establish that the top of this div is related to the top of the screen when you open it and not of the page so that it is always visible without having to upload again? finally I am not allowed to use bootstrap, I would appreciate a response with css or javascript.

this is the style the div has for now:

dialog {
 z-index: 1000;
 position: fixed;
 right: 0;
 left: 0;
 top: 20px;
 margin-right: auto;
 margin-left: auto;
 min-height: 200px;
 width: 90%;
 height: 95vh;
 overflow-y: scroll;
 max-width: 520px;
}

Note: I tried to set the top with

  

px,%, vh and vw

but I have not had good results, the top always stays fixed once established.

    
asked by Andrés Chamorro 01.02.2017 в 19:03
source

2 answers

1

With position: fixed you give a fixed position to a element relative to the viewport , therefore, if you scroll, it will stay in the same position. Another option is to do absolute and through JavaScript get the scrollTop and the scrollLeft of the element to center it and execute these calculations in the event scroll of window.

Using position: fixed

There is a problem with using this method: If the height of the element exceeds the viewheight, the part that overflows will not be visible . Execute the following example to reproduce the problem:

let modal = document.querySelector('.modal');
let width = modal.offsetWidth;
let vw = window.innerWidth;

/* centra la ventana modal horizontalmente */
modal.style.marginLeft = '${(vw - width) / 2}px';
*, *:before, *:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  background: url('http://www.awwwards.com/awards/images/2013/10/Free_People.jpg') repeat-y;
  background-size: contain;
  height: 500vh;
}
.modal {
  background-color: #fff;
  border: 1px solid #eee;
  border-radius: 5px;
  box-shadow: 0 2px 8px 2px rgba(0,0,0,.15);
  display: flex;
  flex-direction: column;
  height: 800px;
  max-width: 400px;
  position: fixed;
  top: 20px;
  width: 80%;
  z-index: 5;
}
.modal .head {
  align-items: center;
  border-bottom: 1px solid #eee;
  display: flex;
  flex: 0 0 50px;
  justify-content: space-between;
  padding: 0 1rem;
}
.modal .head .title {
  display: inline-block;
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-weight: 400;
}
.modal .head .close {
  cursor: pointer;
  font-family: 'segoe ui';
}
.modal .body {
  flex: 1;
  padding: 1rem;
  overflow: auto;
}
.modal .body h2 {
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-weight: 400;
}
.modal .body p {
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-size: 15px;
  margin-top: 25px;
}
.modal .foot {
  align-items: center;
  border-top: 1px solid #eee;
  display: flex;
  flex: 0 0 50px;
  justify-content: flex-end;
  padding: 0 1rem;
}
.modal .foot .btn { margin-left: 10px; }
.btn {
  border-radius: 3px;
  padding: .5rem .75rem;
}
.btn.default {
  background-color: #fff;
  border: 1px solid #ccc;
  color: #444;
}
.btn.primary {
  background-color: #2980b9;
  border: 1px solid transparent;
  color: #fff;
}
<body>
  <div class="modal">
    <header class="head">
      <h3 class="title">Oferta</h3>
      <span class="close">&times;</span>
    </header>
    <article class="body">
      <h2>¡Aproveche nuestras ofertas!</h2>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam porro, hic facilis pariatur maxime praesentium doloribus, esse iste enim distinctio ipsa nobis reiciendis aut similique, eligendi illum, quibusdam nam repellat.
      </p>
    </article>
    <footer class="foot">
      <button class="btn default">Cerrar</button>
      <button class="btn primary">Aceptar</button>
    </footer>
  </div>
</body>

Using position: fixed and max-height

The previous problem can be solved by giving a max-height to the modal so that it does not exceed the viewport at any time. Also, if you want to set a margin, subtract the top and bottom margin from the viewport . This can be done via calc or, if you want to support old browsers, you can do it using JavaScript. Execute the following example to see how it works.

document.addEventListener('DOMContentLoaded', function () {
  let modal = document.querySelector('.modal');
  let width = modal.offsetWidth;
  let vw = window.innerWidth;

  /* centra la ventana modal horizontalmente */
  modal.style.marginLeft = '${(vw - width) / 2}px';
});
*, *:before, *:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  background: url('http://www.awwwards.com/awards/images/2013/10/Free_People.jpg') repeat-y;
  background-size: contain;
  height: 500vh;
}
.modal {
  background-color: #fff;
  border: 1px solid #eee;
  border-radius: 5px;
  box-shadow: 0 2px 8px 2px rgba(0,0,0,.15);
  display: flex;
  flex-direction: column;
  height: 800px;
  max-height: calc(100vh - 40px);
  max-width: 400px;
  position: fixed;
  top: 20px;
  width: 80%;
  z-index: 5;
}
.modal .head {
  align-items: center;
  border-bottom: 1px solid #eee;
  display: flex;
  flex: 0 0 50px;
  justify-content: space-between;
  padding: 0 1rem;
}
.modal .head .title {
  display: inline-block;
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-weight: 400;
}
.modal .head .close {
  cursor: pointer;
  font-family: 'segoe ui';
}
.modal .body {
  flex: 1;
  padding: 1rem;
  overflow: auto;
}
.modal .body h2 {
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-weight: 400;
}
.modal .body p {
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-size: 15px;
  margin-top: 25px;
}
.modal .foot {
  align-items: center;
  border-top: 1px solid #eee;
  display: flex;
  flex: 0 0 50px;
  justify-content: flex-end;
  padding: 0 1rem;
}
.modal .foot .btn { margin-left: 10px; }
.btn {
  border-radius: 3px;
  padding: .5rem .75rem;
}
.btn.default {
  background-color: #fff;
  border: 1px solid #ccc;
  color: #444;
}
.btn.primary {
  background-color: #2980b9;
  border: 1px solid transparent;
  color: #fff;
}
<body>
  <div class="modal">
    <header class="head">
      <h3 class="title">Oferta</h3>
      <span class="close">&times;</span>
    </header>
    <article class="body">
      <h2>¡Aproveche nuestras ofertas!</h2>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam porro, hic facilis pariatur maxime praesentium doloribus, esse iste enim distinctio ipsa nobis reiciendis aut similique, eligendi illum, quibusdam nam repellat.
      </p>
    </article>
    <footer class="foot">
      <button class="btn default">Cerrar</button>
      <button class="btn primary">Aceptar</button>
    </footer>
  </div>
</body>

Using position: fixed and max-height via JS

The rule calc has a pretty good acceptance right now so it can be used without any remorse. However, if your final audience can have very old browsers such as IE < 9, then you probably want to make it compatible. For this you can set the maximum height of the modal according to the viewheight even when the window is resized .

document.addEventListener('DOMContentLoaded', function () {
  adjustModal();
  
  window.addEventListener('resize', adjustModal);
});

function adjustModal () {
  let modal = document.querySelector('.modal');
  let width = modal.offsetWidth;
  let vw = window.innerWidth;
  let vh = window.innerHeight;
  
  /* centra la ventana modal horizontalmente */
  modal.style.marginLeft = '${(vw - width) / 2}px';
  /* Le da un alto máximo al modal */
  modal.style.maxHeight = '${vh - 40}px';
}
*, *:before, *:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  background: url('http://www.awwwards.com/awards/images/2013/10/Free_People.jpg') repeat-y;
  background-size: contain;
  height: 500vh;
}
.modal {
  background-color: #fff;
  border: 1px solid #eee;
  border-radius: 5px;
  box-shadow: 0 2px 8px 2px rgba(0,0,0,.15);
  display: flex;
  flex-direction: column;
  height: 800px;
  max-width: 400px;
  position: fixed;
  top: 20px;
  width: 80%;
  z-index: 5;
}

.modal .head {
  align-items: center;
  border-bottom: 1px solid #eee;
  display: flex;
  flex: 0 0 50px;
  justify-content: space-between;
  padding: 0 1rem;
}
.modal .head .title {
  display: inline-block;
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-weight: 400;
}
.modal .head .close {
  cursor: pointer;
  font-family: 'segoe ui';
}
.modal .body {
  flex: 1;
  padding: 1rem;
  overflow: auto;
}
.modal .body h2 {
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-weight: 400;
}
.modal .body p {
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;
  font-size: 15px;
  margin-top: 25px;
}
.modal .foot {
  align-items: center;
  border-top: 1px solid #eee;
  display: flex;
  flex: 0 0 50px;
  justify-content: flex-end;
  padding: 0 1rem;
}
.modal .foot .btn { margin-left: 10px; }
.btn {
  border-radius: 3px;
  padding: .5rem .75rem;
}
.btn.default {
  background-color: #fff;
  border: 1px solid #ccc;
  color: #444;
}
.btn.primary {
  background-color: #2980b9;
  border: 1px solid transparent;
  color: #fff;
}
<body>
  <div class="modal">
    <header class="head">
      <h3 class="title">Oferta</h3>
      <span class="close">&times;</span>
    </header>
    <article class="body">
      <h2>¡Aproveche nuestras ofertas!</h2>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam porro, hic facilis pariatur maxime praesentium doloribus, esse iste enim distinctio ipsa nobis reiciendis aut similique, eligendi illum, quibusdam nam repellat.
      </p>
    </article>
    <footer class="foot">
      <button class="btn default">Cerrar</button>
      <button class="btn primary">Aceptar</button>
    </footer>
  </div>
</body>

You can see it running more conveniently in this Fiddle .

    
answered by 02.02.2017 / 15:05
source
1

Personally create a container for your div.dialog that occupies 100% of window and thus prevent the user from clicking on another button while your dialogue is visible. Inside this container it will be quite easy to position a div centered.

I leave you an example code:

.dialog-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
}

.dialog {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200px;
  height: 200px;
  transform: translate3d(-50%, -50%, 0);
}
    
answered by 02.02.2017 в 09:39