Ching Ching
Ching Ching

Reputation: 1049

CSS make DIV position fixed inside DIV with PERSPECTIVE propertie

i have a problem for getting #fixed with position:fixed relative to #container

check this fiddle out : https://jsfiddle.net/a1zoghs0/2/

i know that, if i put #fixed outside of #container,

it will had position:fixed. just like this fiddle : https://jsfiddle.net/xc879rbm/1/

but unluckly, i have an issue where this method can't working. is it possible to put this inside #container and still enable position:fixed relative to #container?

is there anything wrong with my code?

thanks in advance...

Upvotes: 4

Views: 5982

Answers (4)

qbolec
qbolec

Reputation: 5134

Here is my solution. I'm not exactly sure of all math details in it, but it looks quite robust to resizing of the window.

The main trick is to put the header so far away and make it so big, that movements of the viewport do not affect it's position much - think about moon on the sky, which is big and far away, and thus your movements of the head do not affect it's position.

body{
  margin:0; /* without it your container will not cover full body */
}
#container {
    width:100vw; /* probably 100% would be ok here */
    height:100vh; /* 100% would not be ok here, 
                     as we need to center perspective viewport 
                     w.r.t. screen- not w.r.t. whole long page content */
    /* this makes math easier to me */
    perspective:1px; 
    perspective-origin:0 0;
    /* we want container to be a window through which you watch
       the scrolling world */
    overflow-y:scroll;
    /* we don't want scrollbar at the bottom, as it would again force
       us to use calc for perspective-origin-y.
       Frankly, I do not know why the scrollbar appears at all */
    overflow-x:hidden;
    /* This is to allow positioning of layers relatively to container*/
    position:relative;
}

.parallaxBase {
    width:100%; 
    position:absolute;
    top:200px;  
 }

.parallaxBack {
    height:100vh;
    /* The general formula to keep size intact is scale(perspective-z)
       so in our case it is scale(1+1) */
    transform:translateZ(-1px) scale(2);
    transform-origin: 0 0;
}

#background {background:red; height:200px; padding-top:100px; }
#content {background:yellow; }
#fixed {background:green; 
  width:100%; 
  height:40px; 
  /* this is not so much to make it sticky,
     it is rather to not push the parallaxBack div lower,
     and to make sure that header is not occluded by elements
     which have position:absolute like parallaxBase,
     as even z-index:1 won't help you if you have position:static
      */
  position:absolute; 
  top:0px; 
  z-index:1;
  /* Now the main idea:
     we push the navbar 1023px to the back, but at the same time,
     we make it (1023+1) times bigger, which makes it appear in
     original size.*/
  transform: scale(1024) translateZ(-1023px);
  transform-origin: 0 0;
 }
<div id="container">
  <div id="fixed">this is fixed // why not fixed?</div>
  <div class="parallaxBack">
    <div id="background"> this is parallax</div>
  </div>
  <div class="parallaxBase">
    <div id="content">
  this is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is content
  this is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is content
    </div>
  </div>
</div>
You might want to play with it in https://jsfiddle.net/7L8ndtuv/2/

I also recommend reading https://developers.google.com/web/updates/2017/03/custom-scrollbar which inspired my answer.

Upvotes: 3

Asons
Asons

Reputation: 87191

Since you can't have the fixed inside, Why does perspective changes fixed position in CSS?, I suggest you add an extra wrapper for your javascript overlay function.

Since you can't have the fixed inside, Why does perspective changes fixed position in CSS?, just place them outside your container (as in below sample), as I can't see the point adding a second wrapper because the fixed div is relative to the window anyway.

#container {
	width:100%;
	height:100%;
	perspective:300px;
 	perspective-origin:50% 50%;
  overflow-y:scroll;
}

.parallaxBase {
    width:100%; 
    position:absolute; top:200px; left:50%;
    transform:translateZ(0);
  	transform:translateX(-50%);

 }

.parallaxBack {
    height:100vh;
    transform:translateZ(-300px) scale(2);

}

#background {background:red; height:200px; padding-top:100px; }
#content {background:yellow; }
#fixed {background:green; 
  width:100%; height:40px; position:fixed; z-index:1; top: 0; left: 0;
 }

#overlay {
width:200px; height:200px; background:purple;
position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); }
<div id="fixed">this is fixed // why not fixed?</div>
<div id="container">
  <div class="parallaxBack">
    <div id="background"> this is parallax</div>
  </div>
  <div class="parallaxBase">
    <div id="content">
      this is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is content
      this is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is contentthis is content
    </div>
  </div>
</div>
<div id="overlay">
  this is overlay
</div>

Upvotes: 2

KarelG
KarelG

Reputation: 5244

The issue is that the wrapper (the div#container box) around the element of which you want to have a fixed position overrules its effect by the next css property:

perspective: 300px;

This is the culprit. When you check the documentation of it, it mentions the next line:

Using this property with a value different than 0 and none creates a new stacking context. source: MDN - CSS perspective

The use of position: fixed has the same behavior, which leads to conflicts.

fixed Do not leave space for the element. Instead, position it at a specified position relative to the screen's viewport and don't move it when scrolled. When printing, position it at that fixed position on every page. This value always create a new stacking context. source: MDN - CSS position

When you remove the above line, you will see that the element is now fixed to the viewport. But that would ruin your parallax background ...

The only solution to solve it is to add an another container on the top of it and use a separate div for your fixed element.

<div id="wrapper">
    <div id="fixed">this is fixed // why not fixed?</div>
    <div id="container">
        <div class="parallaxBack">
            ....
        </div>
    </div>
</div>

And use the position: fixed rule on your div#fixed.

Upvotes: 2

Sune S.-T.
Sune S.-T.

Reputation: 235

position:fixed is relative to the window and not a parent element. If you want to fix an element in a parent element, make the parent element position:relative and the element, you want to fix position:absolute;top:0px;.

Upvotes: 0

Related Questions