Short answer: no. (It is now possible with CSS transform. See the edit below)
Long answer: The problem with using "fixed" positioning is that it takes the element out of flow. thus it can't be re-positioned relative to its parent because it's as if it didn't have one. If, however, the container is of a fixed, known width, you can use something like:
#fixedContainer {
position: fixed;
width: 600px;
height: 200px;
left: 50%;
top: 0%;
margin-left: -300px; /*half the width*/
}
http://jsfiddle.net/HFjU6/1/
Edit (03/2015):
This is outdated information. It is now possible to center content of an dynamic size (horizontally and vertically) with the help of the magic of CSS3 transform. The same principle applies, but instead of using margin to offset your container, you can use translateX(-50%)
. This doesn't work with the above margin trick because you don't know how much to offset it unless the width is fixed and you can't use relative values (like 50%
) because it will be relative to the parent and not the element it's applied to. transform
behaves differently. Its values are relative to the element they are applied to. Thus, 50%
for transform
means half the width of the element, while 50%
for margin is half of the parent's width. This is an IE9+ solution
Using similar code to the above example, I recreated the same scenario using completely dynamic width and height:
.fixedContainer {
background-color:#ddd;
position: fixed;
padding: 2em;
left: 50%;
top: 0%;
transform: translateX(-50%);
}
If you want it to be centered, you can do that too:
.fixedContainer {
background-color:#ddd;
position: fixed;
padding: 2em;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
Demos:
jsFiddle: Centered horizontally only
jsFiddle: Centered both horizontally and vertically
Original credit goes to user aaronk6 for pointing it out to me in this answer
Theory
Looking at current implementation of the pinterest site (it might change in the future), when you open the overlay a noscroll
class is applied to the body
element and overflow: hidden
is set, thus body
is no longer scrollable.
The overlay (created on-the-fly or already inside the page and made visible via display: block
, it makes no difference) has position : fixed
and overflow-y: scroll
, with top
, left
, right
and bottom
properties set to 0
: this style makes the overlay fill the whole viewport.
The div
inside the overlay is instead just in position: static
then the vertical scrollbar you see is related to that element. As a result the content is scrollable but overlay remains fixed.
When you close the zoom you hide the overlay (via display: none
) and then you could also entirely remove it via javascript (or just the content inside, it's up to you how to inject it).
As a final step you have to also remove the noscroll
class to the body
(so the overflow property returns to its initial value)
Code
Codepen Example
(it works by changing the aria-hidden
attribute of the overlay in order to show and hide it and to increase its accessibility).
Markup
(open button)
<button type="button" class="open-overlay">OPEN LAYER</button>
(overlay and close button)
<section class="overlay" aria-hidden="true">
<div>
<h2>Hello, I'm the overlayer</h2>
...
<button type="button" class="close-overlay">CLOSE LAYER</button>
</div>
</section>
CSS
.noscroll {
overflow: hidden;
}
.overlay {
position: fixed;
overflow-y: scroll;
top: 0; right: 0; bottom: 0; left: 0; }
[aria-hidden="true"] { display: none; }
[aria-hidden="false"] { display: block; }
Javascript (vanilla-JS)
var body = document.body,
overlay = document.querySelector('.overlay'),
overlayBtts = document.querySelectorAll('button[class$="overlay"]');
[].forEach.call(overlayBtts, function(btt) {
btt.addEventListener('click', function() {
/* Detect the button class name */
var overlayOpen = this.className === 'open-overlay';
/* Toggle the aria-hidden state on the overlay and the
no-scroll class on the body */
overlay.setAttribute('aria-hidden', !overlayOpen);
body.classList.toggle('noscroll', overlayOpen);
/* On some mobile browser when the overlay was previously
opened and scrolled, if you open it again it doesn't
reset its scrollTop property */
overlay.scrollTop = 0;
}, false);
});
Finally, here's another example in which the overlay opens with a fade-in effect by a CSS transition
applied to the opacity
property. Also a padding-right
is applied to avoid a reflow on the underlying text when the scrollbar disappears.
Codepen Example (fade)
CSS
.noscroll { overflow: hidden; }
@media (min-device-width: 1025px) {
/* not strictly necessary, just an experiment for
this specific example and couldn't be necessary
at all on some browser */
.noscroll {
padding-right: 15px;
}
}
.overlay {
position: fixed;
overflow-y: scroll;
top: 0; left: 0; right: 0; bottom: 0;
}
[aria-hidden="true"] {
transition: opacity 1s, z-index 0s 1s;
width: 100vw;
z-index: -1;
opacity: 0;
}
[aria-hidden="false"] {
transition: opacity 1s;
width: 100%;
z-index: 1;
opacity: 1;
}
Best Answer
You can use react-router to address this scenario:
as an example:
here appbar is fixed on top and other pages are changed as you try to route.
I have used react-addons-css-transition-group for transitions with routes and it is described in this article: https://blog.logrocket.com/routes-animation-transitions-in-react-router-v4-9f4788deb964
please find the animation index.css file in demo
I wrapped pages from a HOC to make routing easier ( PageShell componet)
here is a working example:https://codesandbox.io/s/04p1v46qww
hope this is what you are looking for.