Fixed position but relative to container

Viewed 1241925

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 use position:fixed it fixes the div 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 the div, but when you scroll down the page the element vanishes and doesn't stick to the top as with position:fixed.

Is there a hack or workaround to achieve this?

30 Answers

2019 SOLUTION: You can use position: sticky property.

Here is an example CODEPEN demonstrating the usage and also how it differs from position: fixed.

How it behaves is explained below:

  1. An element with sticky position is positioned based on the user's scroll position. It basically acts like position: relative until an element is scrolled beyond a specific offset, in which case it turns into position: fixed. When it is scrolled back it gets back to its previous (relative) position.

  2. It effects the flow of other elements in the page ie occupies a specific space on the page(just like position: relative).

  3. If it is defined inside some container, it is positioned with respect to that container. If the container has some overflow(scroll), depending on the scroll offset it turns into position:fixed.

So if you want to achieve the fixed functionality but inside a container, use sticky.

It is possible to position an element with fixed position relative to its container if the container is using certain containment rules.

<div class='parent'>
  <div class='child'></div>
</div>
.parent {
  contain: content;
}

.child {
  position: fixed;
  top: 0;
  left: 0;
}

Just take the top and left styles out of the fixed position div. Here's an example

<div id='body' style='height:200%; position: absolute; width: 100%; '>
    <div id='parent' style='display: block; margin: 0px auto; width: 200px;'>
        <div id='content' style='position: fixed;'>content</div>
    </div>
</div> 

The #content div will be sit wherever the parent div sits, but will be fixed there.

You have a solution if you change position: fixed; to position: sticky;

So your code should be:

position: sticky;
top: 0;
right: 0;

now other divs will not slip underneath.

Disclaimer:

This answers just the title: Fixed position but relative to container. For the actual use case the user is asking for position: sticky is the way to go.


https://developer.mozilla.org/en-US/docs/Web/CSS/position

It is positioned relative to the initial containing block established by the viewport, except when one of its ancestors has a transform, perspective, or filter property set to something other than none

You just need to add a transform to the container and the position of the fixed element will be relative to the container. I think a transform: translateX(0); should be enough.

Yes it is possible as long as you don't set the position (top or left, etc.) of your fixed element (you can still use margin to set a relative position, though). Simon Bos posted about this a while ago.

However don't expect fixed element to scroll with non-fixed relatives.

See a demo here.

/* html */

/* this div exists purely for the purpose of positioning the fixed div it contains */
<div class="fix-my-fixed-div-to-its-parent-not-the-body">

     <div class="im-fixed-within-my-container-div-zone">
          my fixed content
     </div>

</div>



/* css */

/* wraps fixed div to get desired fixed outcome */
.fix-my-fixed-div-to-its-parent-not-the-body 
{
    float: right;
}

.im-fixed-within-my-container-div-zone
{
    position: fixed;
    transform: translate(-100%);
}

My project is .NET ASP Core 2 MVC Angular 4 template with Bootstrap 4. Adding "sticky-top" into main app component html (i.e. app.component.html) on the first row worked, as follows:

<div class='row sticky-top'>
    <div class='col-sm-12'>
        <nav-menu-top></nav-menu-top>
    </div>
</div>
<div class="row">
    <div class='col-sm-3'>
        <nav-menu></nav-menu>
    </div>
    <div class='col-sm-9 body-content'>
        <router-outlet></router-outlet>
    </div>
</div>

Is that the convention or did I oversimplify this?

When you use position:fixed CSS rule and try to apply top/left/right/bottom it position the element relative to window.

A workaround is to use margin properties instead of top/left/right/bottom

The magic is to take the screen width minus the container width and divide it by 2:

//1400px is according to container max-width (left can be also right)
.fixed {
  position: fixed;
  right: calc((100vw - 1400px)/2);
}

Note: css calc() function is almost, but not 100% supported. For most use-cases it is definitely supported enough. Click here for more details

Snippet (with a 300px container just to fit this website's widget):

.container {
  max-width: 300px;
  margin-left: auto;
  margin-right: auto;
}


.fixed {
  position: fixed;
  right: calc((100vw - 300px)/2);
}


@media screen and (max-width: 300px) {
  right: 0px;
}
<div style="height: 3000px">
    <div class="container">
        <button class="fixed">
            FIXED CONTENT
        </button>
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Laborum, eum? Animi quidem accusamus minima vel, dolorem suscipit quia accusantium minus harum modi commodi distinctio! Iste voluptatum earum quam voluptate culpa ad, ipsum dolorum recusandae quis atque eligendi necessitatibus magnam nisi dolores beatae qui? Perspiciatis natus cum nostrum in quod odio sapiente doloremque rerum quo dolore tenetur facere, quisquam atque accusamus fugiat eligendi, deleniti nisi minus recusandae distinctio dignissimos! Dicta quos ipsum qui pariatur at vel veritatis veniam quisquam minus modi et voluptas aliquam laborum, cumque in quo magnam sapiente. Expedita ut dolore laboriosam tempora reprehenderit vero eaque blanditiis, cumque voluptatibus, velit nemo, veniam tenetur quisquam numquam adipisci quae odio repellendus neque incidunt! Cum odio corporis soluta voluptate nesciunt, quasi nobis deleniti neque porro expedita fugiat placeat alias autem pariatur animi error, dicta veritatis atque perspiciatis inventore tempora dolor ad! Mollitia in dolorem ipsam eos porro magni perspiciatis possimus maiores, itaque facere ut. Eos culpa eum error quia incidunt repellendus quam possimus, asperiores earum ipsum molestias dicta sint fugit atque veniam dolorum illo? Officia harum sint incidunt totam, reiciendis illum eos maxime sequi neque repellat quis, expedita eum, corporis quaerat nemo qui soluta aspernatur animi. Sint ad rem numquam omnis sit.
    </div>
 </div>

To achieve a similar purpose as the one requested "fixed position relative to container", for me position:fixed was not working since when I scrolled the page the element remained in a fixed position, but you can achieve a similar effect with the overflow feature.

On the snipet below, check how the heading appears fixed when in the parent container, but when you scroll the body it scrolls too

#grandpa{
    width: 100vw;
    height: 120vh;
    background-color:rgb(236, 233, 233);
    overflow:hidden;
}
#parent{
    width: 200px;
    height: 200px;
    background-color:teal;
    overflow:hidden;
}
#child1{
    padding:1em
}
#child2{
    height: 100px;
    background-color:khaki;
    overflow-y:scroll;
}
<div id="grandpa">
    <div id="parent">
        <div id="child1">
            heading
        </div>
        <div id="child2">
            <p>body</p>
            <p>body</p>
            <p>body</p>
            <p>body</p>
            <p>body</p>
            <p>body</p>
            <p>body</p>
            <p>body</p>
        </div>
    </div>
</div>

I am late to answer this question but I am sure this is a common problem to exist in future as well and will definitely help the future searchers.

This can be solved by applying a trick. We can use calc here. Within calc we can use 100 vertical width and subtract 90% of the width and divide by 2. Please make changes to the 90% as per your needs. In your case it can be 100% or 70% whatever depending upon your specific requirement.

.your-class {
  position: fixed;
  right: calc((100vw - 90%)/2);
}

This worked for me. Please note that in my case I intended the floating element to be shifted on the right side. If you want it on the left please use left instead of right.

In my experience, the best way to handle this was to kick the element out of the parent element.

position: sticky didn’t work for me because it didn’t stay fixed on scroll, and position:absolute wasn’t satisfying because it took it out of the document flow.

What I did simply was put the element at the same level as the parent element (so that they are siblings). That way it’s fixed above the element and isn’t taken out of the flow. No additional complicated css or js required.

Check this:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
    </head>
    <body style="width: 1000px !important;margin-left: auto;margin-right: auto">
        <div style="width: 100px; height: 100px; background-color: #ccc; position:fixed;">
        </div>
        <div id="1" style="width: 100%; height: 600px; background-color: #800000">
        </div>
        <div id="2" style="width: 100%; height: 600px; background-color: #100000">
        </div>
        <div id="3" style="width: 100%; height: 600px; background-color: #400000">
        </div>
    </body>
</html>
Related