49

i wonder if anyone has found a solution for this?

i am looking for a solution to attach an element to the top of a scrolling container

HTML:

<div class="container">
  <div class="header">title</div>
  <div class="element">......</div>
  ... (about 10-20 elements) ...
  <div class="element">......</div> 
</div>

all "elements" have position:relative,

the container has the following CSS:

.container {
  position:relative;
  width:200px;
  height:400px;
  overflow-y:scroll;
}

i want the header to stay on top of the container, independant of its scrolling position and the elements scrolling underneath.

the CSS so far:

.header {
  position:absolute; /* scrolling out of view :-( */
  z-index:2;
  background-color:#fff;
}
.element{
  position: relative;
}

all elements are block elements, and i can not move the header outside of the container. jquery is no option at this point.

Justin Blank
  • 1,768
  • 1
  • 15
  • 32
Siggi Gross
  • 491
  • 1
  • 4
  • 4
  • You can do this with jquery. http://www.ruturaj.net/automatic-header-stick-to-scroll-with-jquery/ – Kees Sonnema Jun 29 '12 at 12:08
  • If the container wasn't relatively positioned, the header would be on top of it when absolutely positioned. Could your header be a preceding sibling of the container (well, "container" would now be "content" or sth like this) or your elements have their own container and no `position: relative` on container? – FelipeAls Jun 29 '12 at 13:00
  • @FelipeAlsacreations: position: fixed does not respect position: relative. It is fixed realtively to the document at all times. – Madara's Ghost Jun 29 '12 at 13:13
  • There's no need for `fixed` if I understood OP correctly but `absolute` – FelipeAls Jun 29 '12 at 19:30
  • jQuery is no option ... and as said before, there is no chance to change the structure. position:fixed is fixed to the window, where position:absolute means that the header will scroll out of view if the content is longer than the containers height. – Siggi Gross Jun 30 '12 at 08:42
  • what i need, is that the header stays (visible) on top of the container, no matter if the content is 900px high and scrolled all the way down. at the moment it scrolls with the rest of the content and is out of view if the container is scrolled down. – Siggi Gross Jun 30 '12 at 08:55

10 Answers10

36

I think your solution pass with position:sticky. Seems it's like position:fixed but respects the relative position to his parent.

Unfortunately this is an experimental feature, and is only supported in Chromium. You can see more details in this test page.

The pure css solution that comes into my mind is with a little change of the markup. You can set a container only for the "elements" as this:

<div class="cont_elements">
      <div class="element">......</div>
      .....
</div>

And give the overflow to this inner container. Now, your header sticks at top.

Here's a working demo.

Arkana
  • 2,831
  • 20
  • 35
  • 2
    Beware though, this doesn't currently work in Chrome, it will work in IOS, but not Chrome for Android. See caniuse.com/#feat=css-sticky – Ben Taliadoros Oct 10 '14 at 13:08
  • It seems that in the working demo, the key points are 1. relatively positioned parent element and absolutely positioned header, 2. the subsequent sibling element with specified height and overflow-y. I understand the first key point. Could you please explain the second key point? If any of the height or overflow-y is deleted, the header will not be fixed at the top of the parent container. – uoay Nov 28 '19 at 04:52
9

Here's the solution I came up with using position: sticky (so no IE unfortunately):

https://codepen.io/waterplea/pen/JjjMXzR

The idea is to have a 0 height sticky container on top of the scrolling container, so it sticks but doesn't push any of the content below and then position your stuff absolutely inside it. This way you have width but do not have height, so you can only kinda position something from the top like I did with button in my example.

EDIT: Found a way to make it have 100% height and not push the content below using float. Updated the codepen. Had to use calc(100% - 1px) because of this bug in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1612561

waterplea
  • 3,462
  • 5
  • 31
  • 47
5

The solution in this case would be to pop the title outside of the scrolling element:

<div class="header">title</div>
<div class="container">
    <div class="element">......</div>
    <div class="element">......</div>
</div>

Although you should probably have better semantic elements if possible (just guessing here):

<h3>title</h3>
<ul>
    <li>......</li>
    <li>......</li>
</ul>
Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
5

jQuery UI added a position() utility method just for this purpose that would make your life easier.

$( "#someElement" ).position({
    of:  //Element to position against,
    my:  //which position on the element being positioned,
    at:  //which position on the target element eg: horizontal/vertical,
    offset:  // left-top values to the calculated position, eg. "50 50"
});

Definitely helped me.

Robin Maben
  • 22,194
  • 16
  • 64
  • 99
2

Wrap the elements to scroll with a container: height: 100%; overflow: scroll.

Place the scroll container and the header inside another container, that has a fixed height.

Then position: absolute the header inside the outer container.

.scroll-container {
  height: 100%;
  overflow-y: scroll;
}

.outer-container {
  position: relative;
  width: 200px;
  height: 200px;
}

.header {
  position: absolute; /* relative to outer container */
  background-color: pink;
  width: 100%;
  z-index: 2;
}

.element {
  position: relative;
  background-color: gold;
}
<div class="outer-container">
  <div class="header">title</div>
  <div class="scroll-container">
    <div class="element">......</div>
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div>
    <div class="element">......</div>
    <div class="element">......</div>
    <div class="element">......</div>
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div> 
    <div class="element">......</div>
    <div class="element">......</div>
    <div class="element">......</div>
  </div>
</div>
benhatsor
  • 1,863
  • 6
  • 20
1

The best answer you will ever find for such a solution is from this link How to fixed scroll div after certain height and stop after reach other div? I hope this saves someone some googling time

    var navWrap = $('#navWrap'),
        nav = $('nav'),
        startPosition = navWrap.offset().top,
        stopPosition = $('#stopHere').offset().top - nav.outerHeight();
    
    $(document).scroll(function () {
        //stick nav to top of page
        var y = $(this).scrollTop()
        
        if (y > startPosition) {
            nav.addClass('sticky');
            if (y > stopPosition) {
                nav.css('top', stopPosition - y);
            } else {
                nav.css('top', 0);
            }
        } else {
            nav.removeClass('sticky');
        } 
    });
body {
    height:1600px;
    margin:0;
}
#navWrap {
    height:70px
}
nav {
    height: 70px;
    background:gray;
}
.sticky {
    position: fixed;
    top:0;
}

h1 {
    margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit morb​​,o vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<div id="navWrap">
    <nav>
         <h1>I stick to the top when you scroll down and unstick when you scroll up to my original position</h1>
    </nav>
</div>

<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit morb​​,o vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<br>
<div id="stopHere">
<h3 style="color:red">I want it stop fixed scrolling here. If I'm back to scrolling up, It will follow also to original position.</h3>
</div>
<br>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit morb​​,o vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit morb​​,o vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
<p>Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit morb​​,o vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.</p>
0

#container {
  position: relative;
  width: 400px;
  height: 400px;
}

#fixed {
  position: absolute;
  left: 0px;
  top: 0px;
  Width: 100%;
  height: 100%; // specify your own height
  z-index: 5;
}

#scrollable {
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  overflow-x: hidden;
  z-index: 4;
}
<div id="container">
  <div id="fixed">

  </div>
  <div id="scrollable">

  </div>
</div>
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
0

This is how i've achieved the static position div, within a scrollable div:

<div class="parent">
   <div class="fixFloat">:</div>
   <...some long elements here...>
</div>

.parent {
   position: relative;
   overflow-y: scroll;
}
.fixFloat {
   position: fixed;
   float: right:
}
Yonoss
  • 1,242
  • 5
  • 25
  • 41
0

position:sticky and top:0px works

use position: sticky and top: 0px for your fixed header. With this, the div will be fixed and also takes its height from the parent so the siblings won't overlap with the fixed div.

.parent -> scrolling container

.fixed -> fixed header / fixed div

.content -> overflowing content. Scrollable on enabling overflow: auto in parent.

Note: use overflow: auto instead of overflow: scroll. auto only adds scroll bar if there is a scroll, overflow:scroll shows empty scroll area without any scroll bar if the content do not overflow.

.parent {
  height: 50vh;
  overflow: auto;
  background: yellow;
}

.fixed {
  position: sticky;
  top: 0px;
  background: pink;
}

.content {
  height: 150vh;
}
<div class="parent">
     <div class="fixed">
        Fixed Header
     </div>
     <div class="content">
        <p>content</p>
     </div>
</div>
Anjan Talatam
  • 2,212
  • 1
  • 12
  • 26
-1

Use sticky. Definitely worked!

Parent container:

position:relative;

child container:

position: sticky; // fixed on the page
Dzmitry Kulahin
  • 1,726
  • 2
  • 17
  • 21
Aladdin
  • 1
  • 1