[css] Fixed position but relative to container

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?

This question is related to css position css-position fixed

The answer is


The answer is yes, as long as you don't set left: 0 or right: 0 after you set the div position to fixed.

http://jsfiddle.net/T2PL5/85/

Checkout the sidebar div. It is fixed, but related to the parent, not to the window view point.

_x000D_
_x000D_
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;
}
_x000D_
<div class="wrapper">wrapper
  <div class="sidebar">sidebar</div>
  <div class="main">main</div>
</div>
_x000D_
_x000D_
_x000D_


It's possible if you use JavaScript. In this case, the jQuery plugin Sticky-Kit:


You can give a try to my jQuery plugin, FixTo.

Usage:

$('#mydiv').fixTo('#centeredContainer');

With pure CSS you can't manage to do it; at least I haven't. However you can do it with jQuery very simply. I'll explain my problem, and with a little change you can use it.

So for a start, I wanted my element to have a fixed top (from top of the window), and a left component to inherit from the parent element (because the parent element is centered). To set the left component, just put your element into the parent and set position:relative for the parent element.

Then you need to know how much from the top your element is when the a scroll bar is on top (y zero scrolled); there are two options again. First is that is static (some number) or you have to read it from the parent element.

In my case it's 150 pixels from top static. So when you see 150 it's how much is the element from the top when we haven't scrolled.

CSS

#parent-element{position:relative;}
#promo{position:absolute;}

jQuery

$(document).ready(function() { //This check window scroll bar location on start
    wtop=parseInt($(window).scrollTop());
    $("#promo").css('top',150+wtop+'px');

});
$(window).scroll(function () { //This is when the window is scrolling
    wtop=parseInt($(window).scrollTop());
    $("#promo").css('top',150+wtop+'px');
});

Another weird solution to achieve a relative fixed position is converting your container into an iframe, that way your fixed element can be fixed to it's container's viewport and not the entire page.


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):

_x000D_
_x000D_
.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;
}
_x000D_
<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>
_x000D_
_x000D_
_x000D_


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


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:

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

Is that the convention or did I oversimplify this?


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.


I have the same issue, one of our team members gives me a solution. To allowed the div fix position and relative to other div, our solution is to use a father container wrap the fix div and scroll div.

<div class="container">
  <div class="scroll"></div>
  <div class="fix"></div>
</div>

css

.container {
  position: relative;
  flex:1;
  display:flex;
}

.fix {
  prosition:absolute;
}

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.


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.


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 :)

TEST


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.


I had to do this with an advertisement that my client wanted to sit outside of the content area. I simply did the following and it worked like a charm!

<div id="content" style="position:relative; width:750px; margin:0 auto;">
  <div id="leftOutsideAd" style="position:absolute; top:0; left:-150px;">
    <a href="#" style="position:fixed;"><img src="###" /></a>
  </div>
</div>

I did something like that awhile back. I was pretty new to JavaScript, so I'm sure you can do better, but here is a starting point:

function fixxedtext() {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        if (document.body.offsetWidth > 960) {
            var width = document.body.offsetWidth - 960;
            width = width / 2;
            document.getElementById("side").style.marginRight = width + "px";
        }
        if (document.body.offsetWidth < 960) {
            var width = 960 - document.body.offsetWidth;
            document.getElementById("side").style.marginRight = "-" + width + "px";
        }
    }
    else {
        if (window.innerWidth > 960) {
            var width = window.innerWidth - 960;
            width = width / 2;
            document.getElementById("side").style.marginRight = width + "px";
        }
        if (window.innerWidth < 960) {
            var width = 960 - window.innerWidth;
            document.getElementById("side").style.marginRight = "-" + width + "px";
        }
    }
    window.setTimeout("fixxedtext()", 2500)
}

You will need to set your width, and then it gets the window width and changes the margin every few seconds. I know it is heavy, but it works.


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.


This is easy (as per HTML below)

The trick is to NOT use top or left on the element (div) with "position: fixed;". If these are not specified, the "fixed content" element will appear RELATIVE to the enclosing element (the div with "position:relative;") INSTEAD OF relative to the browser window!!!

<div id="divTermsOfUse" style="width:870px; z-index: 20; overflow:auto;">
    <div id="divCloser" style="position:relative; left: 852px;">
        <div style="position:fixed; z-index:22;">
            <a href="javascript:hideDiv('divTermsOfUse');">
                <span style="font-size:18pt; font-weight:bold;">X</span>
            </a>
        </div>
    </div>
    <div>  <!-- container for... -->
         lots of Text To Be Scrolled vertically...
         bhah! blah! blah!
    </div>
</div>

Above allowed me to locate a closing "X" button at the top of a lot of text in a div with vertical scrolling. The "X" sits in place (does not move with scrolled text and yet it does move left or right with the enclosing div container when the user resizes the width of the browser window! Thus it is "fixed" vertically, but positioned relative to the enclosing element horizontally!

Before I got this working the "X" scrolled up and out of sight when I scrolled the text content down.

Apologies for not providing my javascript hideDiv() function, but it would needlessly make this post longer. I opted to keep it as short as possible.


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>

I created a jsfiddle to demostrate how this works using transform.

HTML

<div class="left">
    Content
</div>
<div class="right">
<div class="fixedContainer">
    X
</div>
    Side bar
</div>

CSS

body {
  margin: 0;
}
.left {
  width: 77%;
  background: teal;
  height: 2000px;
}
.right {
  width: 23%;
  background: yellow;
  height: 100vh;
  position: fixed;
  right: 0;
  top: 0;
}
.fixedContainer {
    background-color:#ddd;
    position: fixed;
    padding: 2em;
    //right: 0;
    top: 0%;
    transform: translateX(-100px);
}

jQuery

$('.fixedContainer').on('click', function() {
    $('.right').animate({'width': '0px'});
  $('.left').animate({'width': '100%'});
});

https://jsfiddle.net/bx6ktwnn/1/


I have created this jQuery plugin to solve a similar issue I was having where I had a centered container (tabular data), and I wanted the header to fix to the top of the page when the list was scrolled, yet I wanted it anchored to the tabular data so it would be wherever I put the container (centered, left, right) and also allow it to move left and right with the page when scrolled horizontally.

Here is the link to this jQuery plugin that may solve this problem:

https://github.com/bigspotteddog/ScrollToFixed

The description of this plugin is as follows:

This plugin is used to fix elements to the top of the page, if the element would have scrolled out of view, vertically; however, it does allow the element to continue to move left or right with the horizontal scroll.

Given an option marginTop, the element will stop moving vertically upward once the vertical scroll has reached the target position; but, the element will still move horizontally as the page is scrolled left or right. Once the page has been scrolled back down passed the target position, the element will be restored to its original position on the page.

This plugin has been tested in Firefox 3/4, Google Chrome 10/11, Safari 5, and Internet Explorer 8/9.

Usage for your particular case:

<script src="scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery-scrolltofixed-min.js" type="text/javascript"></script>

$(document).ready(function() {
    $('#mydiv').scrollToFixed();
});

Two HTML elements and pure CSS (modern browsers)

See this jsFiddle example. Resize and see how the fixed elements even move with the floated elements they are in. Use the inner-most scroll bar to see how the scroll would work on a site (fixed elements staying fixed).

As many here have stated, one key is not setting any positional settings on the fixed element (no top, right, bottom, or left values).

Rather, we put all the fixed elements (note how the last box has four of them) first in the box they are to be positioned off of, like so:

<div class="reference">
  <div class="fixed">Test</div>
  Some other content in.
</div>

Then we use margin-top and margin-left to "move" them in relation to their container, something like as this CSS does:

.fixed {
    position: fixed;
    margin-top: 200px; /* Push/pull it up/down */
    margin-left: 200px; /* Push/pull it right/left */
}

Note that because fixed elements ignore all other layout elements, the final container in our fiddle can have multiple fixed elements, and still have all those elements related to the top left corner. But this is only true if they are all placed first in the container, as this comparison fiddle shows that if dispersed within the container content, positioning becomes unreliable.

Whether the wrapper is static, relative, or absolute in positioning, it does not matter.


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:

_x000D_
_x000D_
/* Main site body */_x000D_
.wrapper {_x000D_
    width: 940px;_x000D_
    margin: 0 auto;_x000D_
    position: relative; /* Ensure absolute positioned child elements are relative to this*/_x000D_
}_x000D_
_x000D_
/* Absolute positioned wrapper for the element you want to fix position */_x000D_
.fixed-wrapper {_x000D_
    width: 220px;_x000D_
    position: absolute;_x000D_
    top: 0;_x000D_
    left: -240px; /* Move this out to the left of the site body, leaving a 20px gutter */_x000D_
}_x000D_
_x000D_
/* The element you want to fix the position of */_x000D_
.fixed {_x000D_
    width: 220px;_x000D_
    position: fixed;_x000D_
    /* Do not set top / left! */_x000D_
}
_x000D_
<div class="wrapper">_x000D_
    <div class="fixed-wrapper">_x000D_
        <div class="fixed">_x000D_
            Content in here will be fixed position, but 240px to the left of the site body._x000D_
        </div>_x000D_
    </div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

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!


/* 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%);
}

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to position

How does the "position: sticky;" property work? React Native absolute positioning horizontal centre RecyclerView - Get view at particular position RecyclerView - How to smooth scroll to top of item on a certain position? How to find index of STRING array in Java from a given value? Insert node at a certain position in a linked list C++ How to position the Button exactly in CSS Float a DIV on top of another DIV Iframe positioning css - position div to bottom of containing div

Examples related to css-position

How does the "position: sticky;" property work? How to stick table header(thead) on top while scrolling down the table rows with fixed header(navbar) in bootstrap 3? CSS z-index not working (position absolute) Relative div height How can I make the contents of a fixed element scrollable only when it exceeds the height of the viewport? How to position the Button exactly in CSS How to make fixed header table inside scrollable div? Absolute positioning ignoring padding of parent Have a fixed position div that needs to scroll if content overflows How to make div fixed after you scroll to that div?

Examples related to fixed

How to fix a header on scroll Fixed header table with horizontal scrollbar and vertical scrollbar on How to make a div have a fixed size? parent & child with position fixed, parent overflow:hidden bug Stop fixed position at footer Fixed positioned div within a relative parent div Fixed position but relative to container HTML table with horizontal scrolling (first column fixed) How can I fix the form size in a C# Windows Forms application and not to let user change its size?