Fixed position but relative to container
Solution 1
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*/
}
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
Solution 2
Actually this is possible and the accepted answer only deals with centralising, which is straightforward enough. Also you really don't need to use JavaScript.
This will let you deal with any scenario:
Set everything up as you would if you want to position: absolute inside a position: relative container, and then create a new fixed position div inside the div with position: absolute
, but do not set its top and left properties. It will then be fixed wherever you want it, relative to the container.
For example:
/* Main site body */
.wrapper {
width: 940px;
margin: 0 auto;
position: relative; /* Ensure absolute positioned child elements are relative to this*/
}
/* Absolute positioned wrapper for the element you want to fix position */
.fixed-wrapper {
width: 220px;
position: absolute;
top: 0;
left: -240px; /* Move this out to the left of the site body, leaving a 20px gutter */
}
/* The element you want to fix the position of */
.fixed {
width: 220px;
position: fixed;
/* Do not set top / left! */
}
<div class="wrapper">
<div class="fixed-wrapper">
<div class="fixed">
Content in here will be fixed position, but 240px to the left of the site body.
</div>
</div>
</div>
Sadly, I was hoping this thread might solve my issue with Android's WebKit rendering box-shadow blur pixels as margins on fixed position elements, but it seems it's a bug.
Anyway, I hope this helps!
Solution 3
Yes, according to the specs, there is a way.
While I agree that Graeme Blackwood's should be the accepted answer, because it practically solves the issue, it should be noted that a fixed element can be positioned relatively to its container.
I noticed by accident that when applying
-webkit-transform: translateZ(0);
to the body, it made a fixed child relative to it (instead of the viewport). So my fixed elements left
and top
properties were now relative to the container.
So I did some research, and found that the issue was already been covered by Eric Meyer and even if it felt like a "trick", turns out that this is part of the specifications:
For elements whose layout is governed by the CSS box model, any value other than none for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.
http://www.w3.org/TR/css3-transforms/
So, if you apply any transformation to a parent element, it will become the containing block.
But...
The problem is that the implementation seems buggy/creative, because the elements also stop behaving as fixed (even if this bit doesn't seem to be part of specification).
The same behavior will be found in Safari, Chrome and Firefox, but not in IE11 (where the fixed element will still remain fixed).
Another interesting (undocumented) thing is that when a fixed element is contained inside a transformed element, while its top
and left
properties will now be related to the container, respecting the box-sizing
property, its scrolling context will extend over the border of the element, as if box-sizing was set to border-box
. For some creative out there, this could possibly become a plaything :)
Solution 4
The answer is yes, as long as you don't set left: 0
or right: 0
after you set the div position to fixed.
Checkout the sidebar div. It is fixed, but related to the parent, not to the window view point.
body {
background: #ccc;
}
.wrapper {
margin: 0 auto;
height: 1400px;
width: 650px;
background: green;
}
.sidebar {
background-color: #ddd;
float: left;
width: 300px;
height: 100px;
position: fixed;
}
.main {
float: right;
background-color: yellow;
width: 300px;
height: 1400px;
}
<div class="wrapper">wrapper
<div class="sidebar">sidebar</div>
<div class="main">main</div>
</div>
Solution 5
position: sticky
that is a new way to position elements that is conceptually similar to position: fixed
. The difference is that an element with position: sticky
behaves like position: relative
within its parent, until a given offset threshold is met in the viewport.
In Chrome 56 (currently beta as of December 2016, stable in Jan 2017) position: sticky is now back.
https://developers.google.com/web/updates/2016/12/position-sticky
More details are in Stick your landings! position: sticky lands in WebKit.
Zach Nicodemous
Updated on July 22, 2022Comments
-
Zach Nicodemous almost 2 years
I am trying to fix a
div
so it always sticks to the top of the screen, using:position: fixed; top: 0px; right: 0px;
However, the
div
is inside a centered container. When I useposition:fixed
it fixes thediv
relative to the browser window, such as it's up against the right side of the browser. Instead, it should be fixed relative to the container.I know that
position:absolute
can be used to fix an element relative to thediv
, but when you scroll down the page the element vanishes and doesn't stick to the top as withposition:fixed
.Is there a hack or workaround to achieve this?
-
Avatar over 4 years"Tether is a low-level UI library that can be used to position any element on a page next to any other element." github.com/shipshapecode/tether + Demos/Docs at tether.io
-
-
Joseph Marikle almost 13 yearsone problem I can see with this approach is that it relies on a timer (2.5 seconds) and during that time, if the user resizes the window, it will take up to that time for it to correct itself. That's not the best thing when it comes to user experience. Also, if it can be helped, try using event listeners instead of timers.
-
webLacky3rdClass almost 13 yearsLike I said it a OLD script, one of my first, and have not needed to go back a fix it. So it is not the best , but it can be a good starting point.
-
Iain M Norman over 12 yearsWorked beautifully for me. Although I needed mine to the left of and already centered, unfixed div, so just had to decrease the left margin until it was aligned. No stays aligned no matter what the width of the windows. Thanks. +1
-
hobberwickey about 12 yearsWhy the minus? This works perfectly for fixing an element wherever you want in the flow of the DOM. deadlykitten.com/tests/fixedPositionTest.php
-
Eric K about 12 yearsMy ad was 140px wide, so I moved it 150px to the left to give it a little bit of right margin against the edge of the website frame.
-
Flash over 11 years@Joseph any idea why
position:fixed
without specifyingtop
orleft
sometimes works? Some browsers appear to default the element to where it would normally be, if it had normal positioning. stackoverflow.com/questions/8712047/… -
JasonWyatt over 11 yearsI don't think this is accomplishing quite what the OP asked about.
-
mfq over 11 yearswhat about without fixed height and width ? In my case I haven't given any signal width to any container even up to body tag. What solution you will say me to do.
-
Joseph Marikle over 11 years@mfq Unfortunately, this method won't work at all without a known height and width. What you go with will largely depend on what you are trying to center. If it's an image, just use it as a background of a 100% x 100% container. If it's an actual element that is completely dynamic, you will probably have to explore using a javascript solution to get the dimensions.
-
o_O almost 11 yearsNot quite ANY scenario but it's a good start. If there's a lot of space below .wrapper then your .fixed-wrapper will end at the bottom of the parent but your .fixed element will continue to flow out of both containers and into any content below. Like I said, it's a good start, not perfect, but I don't see how this can be accomplished without some js.
-
vvohra87 almost 11 yearsProblem is that the div in question flickers when scrolling.
-
Mr Br almost 11 yearsProbably because scrolling is refreshing too much or too fast. I didn't have that problem tbh, but I can suggest you try with using global "blocker" which would be refreshed for example every 10ms or some time, and set to blocking value every time you make some height change. Of course you have to add if condition to .scroll event that is checking if in this period (10ms) you already scrolled div. I repeat I haven't tried but I believe it could work :) On this way you could stop div from changing it's position too much so that computer can't actually follow, and enough so human eye see's it.
-
vvohra87 almost 11 yearsI already gave your answer +1 mate ;) The pain with attaching a global looping method is really performance. To get something like that to work nicely in older pc's and tablets is painful. Many a time a junior dev at work has written a 'var x' inside such a method resulting in needless memory leaks if the page is left open too long :P But yea your suggestion seems like the only real option.
-
Mr Br almost 11 yearsYou got point with global loops; isn't good, I agree. I just like to think about this kind of problems, that's why I wrote another suggestion :) Tbh, now looking it little better, I would avoid it xD I got another solution now. What you say about setting setTimeout() on scroll event which calls func. that makes div movement..also you use global blocker which is set to true while waiting for timeout and when timeout is called you return blocker to false which enables another call after some time...on this way you wouldn't use global loop but still have control on frequency of div movement.
-
vvohra87 almost 11 yearsIt's more elegant but I find it hard to accept. This is the sort of thing I expect the html and css specs to handle tbh. Hate the fact that js is involved in the first place!
-
Francesco Frapporti over 10 years@JosephMarikle I guess you should give a try to my answer below, and perhaps update the "short answer", because this little hack is working perfectly fine for webkit, and many times it's all one needs.
-
Joseph Marikle over 10 years@FrancescoFrapporti That's a nice CSS hack but I think I'll keep my answer as is for a couple of reasons. For one, transform is not w3c standard (draft only) and thus subject to change. With behavior being undefined and this being (as far as I can see) a side effect of the intended style, this has potential to break at some point. The second reason is that this is a webkit only solution. Thank you for adding your answer though. plurality of solutions is what makes these kind of questions so useful to future developers trying to find a solution to their current bugs and development issues.
-
Zach Saucier over 10 yearsThis enabled me to create a table with fixed headers inside of a container
-
Zuhaib Ali over 10 yearsThis doesn't play well with fluid design, however.
-
Mirage about 10 yearsi tried to do this, but as and when i scroll down, the header which i had applied fixed(with parent absolute to which parent was relative) didn't move as i scroll.
-
Anish Patel about 10 yearsNice, this works for me in Chrome. Any ideas on how to achieve the same in IE? I've tried using translateZ but it didn't in any version of IE.
-
Tallboy almost 10 yearsSame.. does anyone know how to do this in IE? its kind of a pain to detect browser, then systematically show or not show
left:
(considering that messes it up) -
html_programmer over 9 yearsAny reason why this doesn't get more upvotes? Seems the most obvious solution to me.
-
mytharcher over 9 yearsI just meet the opposite condition which I need fixed in relative container but changed by transform property. Your answer is very helpful, thank you!
-
Damien over 9 yearsThis worked for me with a top-right div in Chromium and Firefox, except that the vertical positions of the fixed div were different (on Chromium it was on top of the parent div, on Firefox it was inside).
-
Willster over 9 yearsI have found that adding
left:inherit
to the fixed position element can force the browser to respect the parent's offset. -
Joseph Marikle over 9 years@Willster fascinating! I'd very much like to see a working example. Do you have fiddle set up demonstrating that method?
-
jjenzz about 9 years@Francesco Frapporti seems this no longer works... in the latest version of Chrome anyway (Version 42.0.2311.90) :(
-
dmi3y about 9 yearsSolid cross-browser solution, works in IE8 like a charm.
-
Alexandre Bourlier almost 9 yearsWhat about cross browser compatibility. Did any of you checked this?
-
Philip Stratford almost 9 yearsBy accident, I wrapped the
<div>
withposition:absolute
inside the<div>
withposition:fixed
instead, and that works perfectly well, even when resizing the window, etc., at least in Chrome and IE. So it's: <div style="position:relative"> <div style="position:fixed"> <div style="position:absolute;top:0px;"></div> </div> </div> -
Rhys about 8 yearsThis is correct but only for the 'positioning' of the fixed element. It will not respect the container width or resize in any way. For example, If you have a fluid wrapper with max-width:1000px; margin:auto; this will not work. If everything can be a fixed width, then yes this will solve your problem.
-
Jason Frank almost 8 years@AlexandreBourlier Yes, this worked well for me for a fixed element in Chrome, Firefox, and IE11 at least.
-
Ananda Prasad Bandaru over 7 yearsWorked perfectly. Had to add margin-left:X% to bring the element to the right of the container
-
Kyle Vassella over 6 yearsI still have the problem of my width collapsing when I give an element a position:fixed;. Without giving a hard width of 1140px; (which works, but if screen is resized, width is too long), how can I set the original width (1140px) back to my fixed element and still retain responsive width?
-
Kyle Vassella over 6 yearsBut by setting all these hard widths, don't we lose the responsiveness? Is there a way to implement a responsive-width fixed div? Using percentages hasn't worked for me, since width:100% means 100% of the viewport width, not the width of my bootstrap container that my fixed element is a child of.
-
timebandit almost 6 yearsHow does this work as according to w3c
An element with position: fixed; is positioned relative to the viewport
? Please enlighten me. -
Shawn almost 6 yearsDon't understand what is the point of
position:fixed
here. Onlyposition: absolute
is needed to achieve the same. -
Shawn almost 6 years@timebandit it is still relative to the viewport. It's just that without specifying
top
andleft
, it's positioned based on parent's position by default. -
ricks over 5 yearsThis makes life so much easier, the only issue is that sticky is not supported in Internet Explorer or Edge 15 and earlier versions.
-
Yarin over 5 years
position:sticky
is great. Supported by all browsers except IE caniuse.com/#feat=css-sticky -
fat_mike about 5 yearsTotally wrong. Sidebar is positioned to the window view point and not the parent view point. Try this with a smaller wrapper in height. jsfiddle.net/xf0jygcz
-
Vladislav Gritsenko about 5 yearslol, so old api, and you save my day... im' using it for fixed columns for flex tables.
-
Fikret almost 5 years"within its parent" - is it possible to stay sticky element at top, either if parent scrolled up became invisible?
-
dave0688 almost 5 yearsNice solution. I didn't know about
position: sticky
yet. Helped a lot, thanks! -
TerrorBight about 4 yearsI would add to this - if your not sure whether left/top are being set use style="left:unset;right:unset;top:unset;bottom:unset;"
-
dkellner about 4 yearsI was just about to post this. Good answer! sticky is the way.
-
Johann almost 4 yearsIf you increase the output window size in Codepen, the fixed element is not fixed but moves up. Not good. A better solution keeps it anchored to the bottom of the viewport.
-
Pransh Tiwari almost 4 years@AndroidDev Only the top element is defined to be fixed for the entire page. It is being rendered as desired. The other elements are explanatory examples for different cases.
-
tklives almost 4 yearsThis actually worked for me too! Because what I am working with is anchored to the far right side of the page-wrapper, I just added a
transform: translateX(-300px);
(width of the element I needed fixed) in order to get it where I needed. I'm truly surprised this works, but happy to have found it! -
thiout_p almost 4 yearsPerfect fit, thank you! For anyone wondering: works for Chrome 84.0.4147.89 and Firefox 78.0.2 and Edge 44.18362.449.0
-
nullspace over 3 yearsYou can also achieve this with applying
will-change
-
G-Cyrillus over 3 yearsFF 81 let header scroll up and dessapear, but sticky do work fine.
-
AndreVitorio about 3 yearsIt's important to keep in mind that
position: sticky
won't work if any of the parent elements uses theoverflow: hidden
property. -
Uzumaki Naruto over 2 yearsThankyou so much man. Really appreciate it. <3
-
corwin.amber over 2 years
sticky
is much better because that also allows to setwidth: 100%
, relative to the containingdiv
, which the previous solutions (fixed
with noleft
orright
) do not allow. -
arsdever over 2 yearsThe provided might not have been working 10 years ago. But it's nice to share what works at least now.
-
Shubham Jha over 2 years@arsdever Yes, right.
-
Alex over 2 yearswhat kind of hackery is that?? it totally works! You can use it with click passthrough when you want the absolute div to be invisible (stackoverflow.com/questions/3680429/…)
-
isherwood over 2 years@NikitasIO, your comment is vague and can become obsolete. Better to comment on other answers to explain why they're not valid.
-
mufazmi over 2 yearsWow. It's one of the best answer. Really appreciate it. <3
-
strix25 almost 2 yearsnot sure why is this accepted answer, but it does not work!
-
strix25 almost 2 yearsthis does not work at all
-
strix25 almost 2 yearsposition: sticky is one of the most useless things ever one parent has overflow:hidden and it stops working