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">×</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">×</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">×</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 .