411

I find that when I position an element fixed, it doesn't matter if the parent is positioned relative or not, it will position fixed, relative to the window?

#wrapper { width: 300px; background: orange; margin: 0 auto; position: relative; } #feedback { position: fixed; right: 0; top: 120px; }
<div id="wrapper"> ... <a id="feedback" href="#">Feedback</a> </div>

http://jsbin.com/ibesa3

3
  • 3
    Right answer is here stackoverflow.com/questions/4962266/… Commented Apr 17, 2013 at 10:50
  • 11
    "position:sticky" would be the solution. As of now Apr 2016, Firefox seems to be the only browser that supports this (caniuse.com/#feat=css-sticky). Commented Apr 1, 2016 at 22:27
  • In recent browsers (released after this question was asked), a better solution is available. See the answer labelled 2016 update Commented Aug 30, 2017 at 15:20

10 Answers 10

261

Let me provide answers to both possible questions. Note that your existing title (and original post) ask a question different than what you seek in your edit and subsequent comment.


To position an element "fixed" relative to a parent element, you want position:absolute on the child element, and any position mode other than the default or static on your parent element.

For example:

#parentDiv { position:relative; } #childDiv { position:absolute; left:50px; top:20px; } 

This will position childDiv element 50 pixels left and 20 pixels down relative to parentDiv's position.


To position an element "fixed" relative to the window, you want position:fixed, and can use top:, left:, right:, and bottom: to position as you see fit.

For example:

#yourDiv { position:fixed; bottom:40px; right:40px; } 

This will position yourDiv fixed relative to the web browser window, 40 pixels from the bottom edge and 40 pixels from the right edge.

Sign up to request clarification or add additional context in comments.

8 Comments

oh, hmm... I actually want to mimic a sticky button, when its positioned absolute, when I scroll down, it doesn't sticky ... hmm
@DuckMaestro what about doing it inside of overflown div with scrollbar? position:absolute will make it scroll along with it.
how can i vertically position fixed and horizontally position absolute of parent.
While this solution may in fact have benefited OP, it does not answer the question being asked in the title. The answer below this one is far more accurate and should be marked as the correct one.
You should update your answer since calc helps us resolve this with ease. Assuming that your main container can grow up to 900px for initial values you can set to right: 0px after break point hits css @media screen and (min-width: 901px) { right: calc((100% - 900px) / 2) } this will again get those elements attached to your main container.
|
244

The CSS specification requires that position:fixed be anchored to the viewport, not the containing positioned element.

If you must specify your coordinates relative to a parent, you will have to use JavaScript to find the parent's position relative to the viewport first, then set the child (fixed) element's position accordingly.

ALTERNATIVE: Some browsers have sticky CSS support which limits an element to be positioned within both its container and the viewport. Per the commit message:

sticky ... constrains an element to be positioned inside the intersection of its container box, and the viewport.

A stickily positioned element behaves like position:relative (space is reserved for it in-flow), but with an offset that is determined by the sticky position. Changed isInFlowPositioned() to cover relative and sticky.

Depending on your design goals, this behavior may be helpful in some cases. It is currently a working draft, and has decent support, aside from table elements. position: sticky still needs a -webkit prefix in Safari.

See caniuse for up-to-date stats on browser support.

8 Comments

@rayfranco: It's been a long time though; my guess is the op changed his design to match DuckMaestro's answer (which is a simpler design) and that is why it was accepted?
@Jon, you can actually see the edit history if you click the date-time after the post's "edited" note.
@JohnK I know. By "changed his design" I meant the final code the op used on the site — not a change to the question asked here.
This is not a good solution, -webkit-sticky is no longer supported by Chrome (unless you enable the experimental flag). It may come back at some point, but until it's officially supported, best to use Grawl's solution.
I've just updated this answer now that sticky has pretty good support.
|
161

2016 Update

It's now possible in modern browsers to position an element fixed relative to its container. An element that has a transform property acts as the viewport for any of its fixed position child elements.

Or as the CSS Transforms Module puts it:

For elements whose layout is governed by the CSS box model, any value other than none for the transform property also causes the element to establish a containing block for all descendants. Its padding box will be used to layout for all of its absolute-position descendants, fixed-position descendants, and descendant fixed background attachments.

.context { width: 300px; height: 250px; margin: 100px; transform: translateZ(0); } .viewport { width: 100%; height: 100%; border: 1px solid black; overflow: scroll; } .centered { position: fixed; left: 50%; bottom: 15px; transform: translateX(-50%); }
<div class="context"> <div class="viewport"> <div class="canvas"> <table> <tr> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> </tr> <tr> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> </tr> <tr> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> </tr> <tr> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> <td>stuff</td> </tr> </table> <button class="centered">OK</button> </div> </div> </div>

15 Comments

Doesn't work in IE11
Why would you need to do this when a child element with absolute positioning acts the same within a parent with relative or absolute positioning?
@Sean It's when the parent element has a scroll bar and you want the the fixed position element to stay while the parent element scrolls behind it.
I always just put another div around it, and position absolutely to the outer div, then let the inner div have the scroll bar. There are times when you don't have the control over the HTML, though, so good to know this works!
There are a few different CSS properties that have this effect. Another would be will-change: transform.
|
65

first, set position: fixed and left: 50%, and second — now your start is a center and you can set new position with margin.

3 Comments

Be very careful with this approach! If the fixed element isn't in the viewport it won't work as expected. This fiddle demonstrates the issue if the viewport is too short. jsbin.com/igolur/4/edit
Best solution until sticky is better supported in more browsers.
you can use additional wrapper inside element with left: 50% (.parent) and set left: -50% for its child (.child) and child will be in center. tip: use pointer-events: none for .parent ;)
45

This solution works for me!

 .level1 { position: relative; } .level2 { position: absolute; } .level3 { position: fixed; /* Do not set top / left! */ } 
 <div class='level1'> <div class='level2'> <div class='level3'> Content </div> </div> </div> 

4 Comments

This answer should be on top
Very simple solution. Top notch!
awesomeness +++
This worked for me when setting top on the absolute element, so thanks! I'm trying to piece together why this actually works. I may be wrong, but here's what I've been able to ascertain: * position: fixed positions the element relative to the viewport, and there's no way to change that. * However, if the default value of auto is set for top and bottom, the element is positioned where it should vertically be positioned if it were a static element
19

I know this is super old but after not finding the (pure CSS) answer I was looking for I came up with this solution (partially abstracted from medium.com) and thought it might help others looking to do the same thing.

If you combine @DuckMaestro's answers you can position an element fixed relative to a parent (actually grandparent). Use position: absolute; to position an element inside a parent with position: relative; and then position: fixed; on an element inside the absolute positioned element like so:

HTML

<div class="relative"> <div class="absolute"> <a class="fixed-feedback">This element will be fixed</a> </div> </div> 

CSS

.relative { margin: 0 auto; position: relative; width: 300px; } .absolute { position: absolute; right: 0; top: 0; width: 50px; } .fixed-feedback { position: fixed; top: 120px; width: 50px; } 

EXAMPLE

Like @JonAdams said, the definition of position: fixed requires the element to be positioned relative to the viewport but you can get around the horizontal aspect of that using this solution.

Note: This is different than just setting a right or left value on the fixed element because that would cause it to move horizontally when a window is resized.

3 Comments

This doesn't appear to work the way you claim. The element is still positioning fixed relative to the viewport, NOT the containing element. Its position left/right isn't being changed, so it stays where it is that regard, but it is not, in the true sense, fixed according to its parent. Look at this example, I added a div above the parent div. The div.fixed-feedback remains at 120px from the top of the window. codepen.io/anon/pen/LbvOaY
@SeanKendle, that is correct. If the element was fixed relative to the parent in the truest sense of the word that would just be absolute. In this case it is fixed vertically to the viewport and horizontally to the parent. That is what I was attempting because it is what the question seems to be asking in my estimation. I may be wrong, though.
I agree except where you say that absolute inside the parent translates to essentially fixed, because if it were absolute, scrolling would cause it to move with the rest of the contents of the parent div, not remain stationary as it would in a truly fixed position.
10

Here is an example of Jon Adams suggestion above in order to fix a div (toolbar) to the right hand side of your page element using jQuery. The idea is to find the distance from the right hand side of the viewport to the right hand side of the page element and to keep the right hand side of the toolbar there!

HTML

<div id="pageElement"></div> <div id="toolbar"></div> 

CSS

#toolbar { position: fixed; } .... 

jQuery

function placeOnRightHandEdgeOfElement(toolbar, pageElement) { $(toolbar).css("right", $(window).scrollLeft() + $(window).width() - $(pageElement).offset().left - parseInt($(pageElement).css("borderLeftWidth"),10) - $(pageElement).width() + "px"); } $(document).ready(function() { $(window).resize(function() { placeOnRightHandEdgeOfElement("#toolbar", "#pageElement"); }); $(window).scroll(function () { placeOnRightHandEdgeOfElement("#toolbar", "#pageElement"); }); $("#toolbar").resize(); }); 

1 Comment

@Grawl ..JQuery was born out of dealing with the madness! As CSS matures and browser compliance grow I hope you will be correct.
9

It's an old post but i'll leave here my javascript solution just in case someone need it.


// you only need this function function sticky( _el ){ _el.parentElement.addEventListener("scroll", function(){ _el.style.transform = "translateY("+this.scrollTop+"px)"; }); } // how to make it work: // get the element you want to be sticky var el = document.querySelector("#blbl > div"); // give the element as argument, done. sticky(el);
#blbl{ position:relative; height:200px; overflow: auto; background: #eee; } #blbl > div{ position:absolute; padding:50px; top:10px; left:10px; background: #f00 }
<div id="blbl" > <div><!-- sticky div --></div> <br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br> </div>


Notes

  1. I used transform: translateY(@px) because it should be lightweight to compute, high-performance-animations

  2. I only tried this function with modern browsers, it won't work for old browsers where vendors are required (and IE of course)

Comments

2

I know this is an older post, but I think a good example of what Jiew Meng was trying to do can already be found on this site. Check out the side menu located here: https://stackoverflow.com/faq#questions. Looking at it without getting into it too deep, I can tell javascript attaches a fixed position once the scrolling hits below the anchor tag and removes the fixed positioning if the scrolling goes above that same anchor tag. Hopefully, that will get someone started in the right direction.

Comments

1

With multiple divs I managed to get a fixed-y and absolute-x divs. In my case I needed a div on left and right sides, aligned to a centered 1180px width div.

 <div class="parentdiv" style=" background: transparent; margin: auto; width: 100%; max-width: 1220px; height: 10px; text-align: center;"> <div style=" position: fixed; width: 100%; max-width: 1220px;"> <div style=" position: absolute; background: black; height: 20px; width: 20px; left: 0;"> </div> <div style=" width: 20px; height: 20px; background: blue; position: absolute; right: 0;"> </div> </div> </div> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.