5

I need to position a header to be fixed within the containing parent so that it follows when scrolling. The problem is that

position:fixed

fixes the position to the browser, not the parent. What this is resulting in is that when I have a container that has a horizontal scroll for overflow in the width (the content is wider than the container), my fixed header does not have the overflow-scroll as the content of the table does.

See this fiddle demo

So the goal here is to fix the position of the header, but fixed relative to it's parent container. In this fiddle, you can see that I've commented out a block of css:

.container{

     /*-webkit-transform: translateZ(0);
     -moz-transform: translateZ(0);
     -ms-transform: translateZ(0);
     transform: translateZ(0);*/

     -webkit-transform: none;
     -moz-transform: none;
     -ms-transform: none;
     transform: none;   
}

If you replace the current css block (with transform set to none) with the one with translateZ, the header will get positioned within it's parent container, but is no longer fixed.

Anyone know how to solve this? Preferred solution would be CSS/HTML only and avoid JS but if nothing else, then JS is of course what I need to go with!

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Jonathan Lind
  • 205
  • 5
  • 15
  • 7
    to fix something relative to ists parent, you'd need `position:relative` on the parent and `position:absolute` on the child – atmd Jul 21 '15 at 10:08

3 Answers3

2

CSS can't do this by itself.

Position: fixed works in relation to the viewport, not it's containing element.

I've seen an attempt to solve this problem using the CSS3 transform property, but (as you noted in your comment to my first answer) it doesn't seem to work.

I understand you can't use any client-side library but that's the only solution available to my knowledge. For you and others who may one day need this, here's a solution that works. It employs a bit of jQuery:

Positioning an element inside another element with the positioned element fixed along the x and y axes (i.e. position fixed horizontally and vertically).

http://jsfiddle.net/8086p69z/8/

HTML

<div class="moving-article">

    <div class="container">

    <header class="fixed-header">FIXED HEADER</header>

        <ul>
        <li>SCROLL</li>
        <li>SCROLL</li>
        <li>SCROLL</li>
        </ul>    

    </div>

</div>

CSS (relevant section)

.moving-article {
    height: 150px;
    width: 75%;
    overflow-x: scroll;     
}

.fixed-header {
    background: rgba(0,0,0,0.5);
    width: 50%;
    text-align: center;
    line-height: 40px;
    position: absolute;
    top: 0;
    left: 0;
}

.container{
    width: 1000px;
}

jQuery

var leftOffset = parseInt($(".fixed-header").css('left'));
$(window).scroll(function(){
    $('.fixed-header').css({
        'left': $(this).scrollLeft() + leftOffset
    });
});
Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Thank you again @mbnyc, I might have to rethink my options it seems. However this seem to work in some cases, it doesn't work if there is a horizontal overflow on both the header and the content. I need the overflow of the header to be hidden within the container the same way the content of it is. – Jonathan Lind Jul 22 '15 at 06:31
  • Based on your comment, I'm not entirely sure what doesn't work. I filled the fiddle demo tags with content, and the scrolling and positioning mechanisms work fine. Please elaborate. Or maybe replicate the problem in the demo and post the updated link. – Michael Benjamin Jul 22 '15 at 10:01
  • Let's say that the container class is 1000px wide, and you have an overflow scroll horizontally. Then the header should be just as wide, and using the same horizontal scroll as for the content in the container. If you set the width of the header to let's say 100%, then the header will overlap the container and fill up the entire screen. Here is a fiddle of that example: http://jsfiddle.net/8086p69z/12/. Now the point of it all is that the header needs to be "inside" the container, along with the rest of the content. So when you scroll horizontally to view the content, the header follows. – Jonathan Lind Jul 22 '15 at 10:17
  • The answer is to add `position: relative` to the header's parent container (`.container`). Here's the updated fiddle: http://jsfiddle.net/8086p69z/13/ – Michael Benjamin Jul 22 '15 at 11:25
  • When you add position:relative to the parent (.container), you remove the functionality of the header following on scroll. Or does it follow for you on that fiddle? – Jonathan Lind Jul 22 '15 at 12:12
  • Yes, I noticed that, but if your header is set to 100% of the container, why does it matter? It wouldn't be noticeable. Fixing the header in place would only matter if it covered a shorter width than the surrounding content. In this case, you're wanting it to cover the full width. – Michael Benjamin Jul 22 '15 at 12:15
  • Maybe it is unclear what my purpose is with that example. I'm going to use this for a table and so it does matter when the header doesn't follow the scroll. This example has a table instead. http://jsfiddle.net/8086p69z/15/. Now, the intention is to get the header of the table to follow when scrolling vertically And horizontally. – Jonathan Lind Jul 22 '15 at 12:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/83980/discussion-between-mbnyc-and-jonathan-lind). – Michael Benjamin Jul 22 '15 at 14:03
0

set the header's position to 'absolute', and it's parent container (which you want it to be relative to) to 'relative', and set it to stick to the top of the parent with 'top: 0'

CSS:

.container {
  position: relative;
}

.child {
  position: absolute;
  top: 0;
}
Asaf David
  • 3,167
  • 2
  • 22
  • 38
  • 1
    That yields the same result as when using the transform though? The header doesn't follow on scroll. http://jsfiddle.net/8086p69z/3/ – Jonathan Lind Jul 21 '15 at 10:28
  • Maybe I misunderstood, can you explain what exactly are you trying to achieve? – Asaf David Jul 21 '15 at 10:34
  • I need the header to follow the containing parent when scrolling down the window. When the content of my header is wider than the container, it should give me a horizontal scroll (as in the demo) but it should still follow the down-scroll – Jonathan Lind Jul 21 '15 at 10:40
  • So why do you want the header inside the container? You can put it above it, so it will stay fixed in the y-axis, and give it the same x-axis settings (overflow and so) – Asaf David Jul 21 '15 at 11:01
  • That will result in me having one separate scroll bar for the header, and one separate for the content within the container. I'm going to apply this to a table that has an unknown (dynamic) width but is located within a bootstrap container. If the content is too wide, you'll have to scroll horizontally to view the overflowing content (and also the header which should follow the vertical scroll). – Jonathan Lind Jul 21 '15 at 11:05
  • So if I understand correctly your problem is not about the positioning itself but mor about the "overflow"-property... Look into "overflow(-x/-y): hidden|scroll" maybe this solves the issue. – Foaster Jul 22 '15 at 11:44
0

To keep an element fixed within a parent cannot be done with position: fixed because position: fixed takes the element out of the flow and therefore it has no parent. It positions itself relative to the viewport.

To accomplish your goal, while keeping things simple and efficient, you may want to consider Tether, "a client-side library to make absolutely positioned elements attach to elements in the page efficiently".

Hope this helps. Good luck.

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Thank you @mbnyc, but I can't use a client-side lib. No other suggestions? – Jonathan Lind Jul 21 '15 at 13:41
  • Maybe you can get it done with CSS3'S `transform` property. http://stackoverflow.com/questions/6794000/fixed-position-but-relative-to-container – Michael Benjamin Jul 21 '15 at 13:46
  • Can't get that to work either. Although it is fixed correctly to the container, it is not fixed to the top of it when scrolling. http://jsfiddle.net/8086p69z/5/ – Jonathan Lind Jul 21 '15 at 16:37