Establecer top de un div en relacion a la pantalla

publicado por: Anonymous

tengo un div que aparece al tocar un boton de abrir (similar a un modal), este boton aparece n veces a lo largo de la página, mi problema es que si se ha hecho scroll hacia abajo y se hace clic en el boton de abrir, el div aparece en la parte superior de la pagina y el usuario debe hacer scroll hacia arriba para poder verlo, ¿como podria establecer que el top de ese div este en relacion a la parte superior de la pantalla al momento de abrirlo y no de la pagina para que siempre sea visible sin tener que subir de nuevo? por ultimo no tengo permitido usar bootstrap, agradeceria una respuesta con css o javascript.

este es el estilo que tiene el div por ahora:

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;
}

Nota: he intentado establecer el top con

px, %, vh y vw

pero no he tenido buenos resultados, el top siempre se mantiene fijo una vez establecido.

solución

Con position: fixed le das una posición fija a un elemento relativo al viewport, por ende, si haces scroll éste se mantendrá en la misma posición. Otra opción es hacerlo absolute y mediante JavaScript obtener el scrollTop y el scrollLeft del elemento para así centrarlo y ejecutar éstos cálculos en el evento scroll de window.

Usando position: fixed

Hay un problema con usar éste método: si el alto del elemento supera al viewheight, la parte que se desborda no será visible. Ejecuta el siguiente ejemplo para reproducir el problema:

_x000D_

_x000D_

let modal = document.querySelector('.modal');_x000D_
let width = modal.offsetWidth;_x000D_
let vw = window.innerWidth;_x000D_
_x000D_
/* centra la ventana modal horizontalmente */_x000D_
modal.style.marginLeft = `${(vw - width) / 2}px`;

_x000D_

*, *:before, *:after {_x000D_
  box-sizing: border-box;_x000D_
  margin: 0;_x000D_
  padding: 0;_x000D_
}_x000D_
body {_x000D_
  background: url('http://www.awwwards.com/awards/images/2013/10/Free_People.jpg') repeat-y;_x000D_
  background-size: contain;_x000D_
  height: 500vh;_x000D_
}_x000D_
.modal {_x000D_
  background-color: #fff;_x000D_
  border: 1px solid #eee;_x000D_
  border-radius: 5px;_x000D_
  box-shadow: 0 2px 8px 2px rgba(0,0,0,.15);_x000D_
  display: flex;_x000D_
  flex-direction: column;_x000D_
  height: 800px;_x000D_
  max-width: 400px;_x000D_
  position: fixed;_x000D_
  top: 20px;_x000D_
  width: 80%;_x000D_
  z-index: 5;_x000D_
}_x000D_
.modal .head {_x000D_
  align-items: center;_x000D_
  border-bottom: 1px solid #eee;_x000D_
  display: flex;_x000D_
  flex: 0 0 50px;_x000D_
  justify-content: space-between;_x000D_
  padding: 0 1rem;_x000D_
}_x000D_
.modal .head .title {_x000D_
  display: inline-block;_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-weight: 400;_x000D_
}_x000D_
.modal .head .close {_x000D_
  cursor: pointer;_x000D_
  font-family: 'segoe ui';_x000D_
}_x000D_
.modal .body {_x000D_
  flex: 1;_x000D_
  padding: 1rem;_x000D_
  overflow: auto;_x000D_
}_x000D_
.modal .body h2 {_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-weight: 400;_x000D_
}_x000D_
.modal .body p {_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-size: 15px;_x000D_
  margin-top: 25px;_x000D_
}_x000D_
.modal .foot {_x000D_
  align-items: center;_x000D_
  border-top: 1px solid #eee;_x000D_
  display: flex;_x000D_
  flex: 0 0 50px;_x000D_
  justify-content: flex-end;_x000D_
  padding: 0 1rem;_x000D_
}_x000D_
.modal .foot .btn { margin-left: 10px; }_x000D_
.btn {_x000D_
  border-radius: 3px;_x000D_
  padding: .5rem .75rem;_x000D_
}_x000D_
.btn.default {_x000D_
  background-color: #fff;_x000D_
  border: 1px solid #ccc;_x000D_
  color: #444;_x000D_
}_x000D_
.btn.primary {_x000D_
  background-color: #2980b9;_x000D_
  border: 1px solid transparent;_x000D_
  color: #fff;_x000D_
}

_x000D_

<body>_x000D_
  <div class="modal">_x000D_
    <header class="head">_x000D_
      <h3 class="title">Oferta</h3>_x000D_
      <span class="close">&times;</span>_x000D_
    </header>_x000D_
    <article class="body">_x000D_
      <h2>¡Aproveche nuestras ofertas!</h2>_x000D_
      <p>_x000D_
        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._x000D_
      </p>_x000D_
    </article>_x000D_
    <footer class="foot">_x000D_
      <button class="btn default">Cerrar</button>_x000D_
      <button class="btn primary">Aceptar</button>_x000D_
    </footer>_x000D_
  </div>_x000D_
</body>

_x000D_

_x000D_

_x000D_

Usando position: fixed y max-height

El anterior problema lo puedes solucionar dando un max-height al modal para que no supere el viewport en ningún momento. Además, en caso quieras poner un margen, se resta el margen superior e inferior al viewport. Ésto puedes hacerlo vía calc o, en caso quieras dar soporte a navegadores viejos, puedes hacerlo mediante JavaScript. Ejecuta el suguiente ejemplo para ver su funcionamiento.

_x000D_

_x000D_

document.addEventListener('DOMContentLoaded', function () {_x000D_
  let modal = document.querySelector('.modal');_x000D_
  let width = modal.offsetWidth;_x000D_
  let vw = window.innerWidth;_x000D_
_x000D_
  /* centra la ventana modal horizontalmente */_x000D_
  modal.style.marginLeft = `${(vw - width) / 2}px`;_x000D_
});

_x000D_

*, *:before, *:after {_x000D_
  box-sizing: border-box;_x000D_
  margin: 0;_x000D_
  padding: 0;_x000D_
}_x000D_
body {_x000D_
  background: url('http://www.awwwards.com/awards/images/2013/10/Free_People.jpg') repeat-y;_x000D_
  background-size: contain;_x000D_
  height: 500vh;_x000D_
}_x000D_
.modal {_x000D_
  background-color: #fff;_x000D_
  border: 1px solid #eee;_x000D_
  border-radius: 5px;_x000D_
  box-shadow: 0 2px 8px 2px rgba(0,0,0,.15);_x000D_
  display: flex;_x000D_
  flex-direction: column;_x000D_
  height: 800px;_x000D_
  max-height: calc(100vh - 40px);_x000D_
  max-width: 400px;_x000D_
  position: fixed;_x000D_
  top: 20px;_x000D_
  width: 80%;_x000D_
  z-index: 5;_x000D_
}_x000D_
.modal .head {_x000D_
  align-items: center;_x000D_
  border-bottom: 1px solid #eee;_x000D_
  display: flex;_x000D_
  flex: 0 0 50px;_x000D_
  justify-content: space-between;_x000D_
  padding: 0 1rem;_x000D_
}_x000D_
.modal .head .title {_x000D_
  display: inline-block;_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-weight: 400;_x000D_
}_x000D_
.modal .head .close {_x000D_
  cursor: pointer;_x000D_
  font-family: 'segoe ui';_x000D_
}_x000D_
.modal .body {_x000D_
  flex: 1;_x000D_
  padding: 1rem;_x000D_
  overflow: auto;_x000D_
}_x000D_
.modal .body h2 {_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-weight: 400;_x000D_
}_x000D_
.modal .body p {_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-size: 15px;_x000D_
  margin-top: 25px;_x000D_
}_x000D_
.modal .foot {_x000D_
  align-items: center;_x000D_
  border-top: 1px solid #eee;_x000D_
  display: flex;_x000D_
  flex: 0 0 50px;_x000D_
  justify-content: flex-end;_x000D_
  padding: 0 1rem;_x000D_
}_x000D_
.modal .foot .btn { margin-left: 10px; }_x000D_
.btn {_x000D_
  border-radius: 3px;_x000D_
  padding: .5rem .75rem;_x000D_
}_x000D_
.btn.default {_x000D_
  background-color: #fff;_x000D_
  border: 1px solid #ccc;_x000D_
  color: #444;_x000D_
}_x000D_
.btn.primary {_x000D_
  background-color: #2980b9;_x000D_
  border: 1px solid transparent;_x000D_
  color: #fff;_x000D_
}

_x000D_

<body>_x000D_
  <div class="modal">_x000D_
    <header class="head">_x000D_
      <h3 class="title">Oferta</h3>_x000D_
      <span class="close">&times;</span>_x000D_
    </header>_x000D_
    <article class="body">_x000D_
      <h2>¡Aproveche nuestras ofertas!</h2>_x000D_
      <p>_x000D_
        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._x000D_
      </p>_x000D_
    </article>_x000D_
    <footer class="foot">_x000D_
      <button class="btn default">Cerrar</button>_x000D_
      <button class="btn primary">Aceptar</button>_x000D_
    </footer>_x000D_
  </div>_x000D_
</body>

_x000D_

_x000D_

_x000D_

Usando position: fixed y max-height vía JS

La regla calc tiene una aceptación bastante buena ahora mismo así que se puede usar sin ningún remordimiento. Sin embargo, si tu público final puede tener navegadores muy viejos como IE < 9, entonces es probable que quieras hacerlo compatible. Paa ésto puedes establecer el alto máximo de la modal de acuerdo al viewheight incluso cuando se redimensione la ventana.

_x000D_

_x000D_

document.addEventListener('DOMContentLoaded', function () {_x000D_
  adjustModal();_x000D_
  _x000D_
  window.addEventListener('resize', adjustModal);_x000D_
});_x000D_
_x000D_
function adjustModal () {_x000D_
  let modal = document.querySelector('.modal');_x000D_
  let width = modal.offsetWidth;_x000D_
  let vw = window.innerWidth;_x000D_
  let vh = window.innerHeight;_x000D_
  _x000D_
  /* centra la ventana modal horizontalmente */_x000D_
  modal.style.marginLeft = `${(vw - width) / 2}px`;_x000D_
  /* Le da un alto máximo al modal */_x000D_
  modal.style.maxHeight = `${vh - 40}px`;_x000D_
}

_x000D_

*, *:before, *:after {_x000D_
  box-sizing: border-box;_x000D_
  margin: 0;_x000D_
  padding: 0;_x000D_
}_x000D_
body {_x000D_
  background: url('http://www.awwwards.com/awards/images/2013/10/Free_People.jpg') repeat-y;_x000D_
  background-size: contain;_x000D_
  height: 500vh;_x000D_
}_x000D_
.modal {_x000D_
  background-color: #fff;_x000D_
  border: 1px solid #eee;_x000D_
  border-radius: 5px;_x000D_
  box-shadow: 0 2px 8px 2px rgba(0,0,0,.15);_x000D_
  display: flex;_x000D_
  flex-direction: column;_x000D_
  height: 800px;_x000D_
  max-width: 400px;_x000D_
  position: fixed;_x000D_
  top: 20px;_x000D_
  width: 80%;_x000D_
  z-index: 5;_x000D_
}_x000D_
_x000D_
.modal .head {_x000D_
  align-items: center;_x000D_
  border-bottom: 1px solid #eee;_x000D_
  display: flex;_x000D_
  flex: 0 0 50px;_x000D_
  justify-content: space-between;_x000D_
  padding: 0 1rem;_x000D_
}_x000D_
.modal .head .title {_x000D_
  display: inline-block;_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-weight: 400;_x000D_
}_x000D_
.modal .head .close {_x000D_
  cursor: pointer;_x000D_
  font-family: 'segoe ui';_x000D_
}_x000D_
.modal .body {_x000D_
  flex: 1;_x000D_
  padding: 1rem;_x000D_
  overflow: auto;_x000D_
}_x000D_
.modal .body h2 {_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-weight: 400;_x000D_
}_x000D_
.modal .body p {_x000D_
  font-family: 'segoe ui', 'ubuntu', 'noto sans', system;_x000D_
  font-size: 15px;_x000D_
  margin-top: 25px;_x000D_
}_x000D_
.modal .foot {_x000D_
  align-items: center;_x000D_
  border-top: 1px solid #eee;_x000D_
  display: flex;_x000D_
  flex: 0 0 50px;_x000D_
  justify-content: flex-end;_x000D_
  padding: 0 1rem;_x000D_
}_x000D_
.modal .foot .btn { margin-left: 10px; }_x000D_
.btn {_x000D_
  border-radius: 3px;_x000D_
  padding: .5rem .75rem;_x000D_
}_x000D_
.btn.default {_x000D_
  background-color: #fff;_x000D_
  border: 1px solid #ccc;_x000D_
  color: #444;_x000D_
}_x000D_
.btn.primary {_x000D_
  background-color: #2980b9;_x000D_
  border: 1px solid transparent;_x000D_
  color: #fff;_x000D_
}

_x000D_

<body>_x000D_
  <div class="modal">_x000D_
    <header class="head">_x000D_
      <h3 class="title">Oferta</h3>_x000D_
      <span class="close">&times;</span>_x000D_
    </header>_x000D_
    <article class="body">_x000D_
      <h2>¡Aproveche nuestras ofertas!</h2>_x000D_
      <p>_x000D_
        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._x000D_
      </p>_x000D_
    </article>_x000D_
    <footer class="foot">_x000D_
      <button class="btn default">Cerrar</button>_x000D_
      <button class="btn primary">Aceptar</button>_x000D_
    </footer>_x000D_
  </div>_x000D_
</body>

_x000D_

_x000D_

_x000D_

Puedes verlo en funcionamiento más cómodamente en éste Fiddle.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *