How can I make a div stick to the top of the screen once it's been scrolled to?
Asked Answered
C

26

436

I would like to create a div, that is situated beneath a block of content but that once the page has been scrolled enough to contact its top boundary, becomes fixed in place and scrolls with the page.

Connivent answered 1/8, 2009 at 7:54 Comment(6)
As of June 2014, the Sticky-kit jQuery plugin is one of the easiest options, providing an extremely low barrier to entry and lots of features. Great place to start if you're looking for an easy way to get off the ground quickly.Africa
CSS tricks: css-tricks.com/scroll-fix-contentLandel
Adding CSS position: sticky; top:0; works in most browsers in January 2017.Arrowwood
Holy crap, that position: sticky; thing is magical.Aconite
it can be because of display flex, read this : https://mcmap.net/q/80445/-how-does-the-quot-position-sticky-quot-property-workFastback
position: sticky; top:0; in a relative container works for me.Gamali
L
366

You could use simply css, positioning your element as fixed:

.fixedElement {
    background-color: #c0c0c0;
    position:fixed;
    top:0;
    width:100%;
    z-index:100;
}

Edit: You should have the element with position absolute, once the scroll offset has reached the element, it should be changed to fixed, and the top position should be set to zero.

You can detect the top scroll offset of the document with the scrollTop function:

$(window).scroll(function(e){ 
  var $el = $('.fixedElement'); 
  var isPositionFixed = ($el.css('position') == 'fixed');
  if ($(this).scrollTop() > 200 && !isPositionFixed){ 
    $el.css({'position': 'fixed', 'top': '0px'}); 
  }
  if ($(this).scrollTop() < 200 && isPositionFixed){
    $el.css({'position': 'static', 'top': '0px'}); 
  } 
});

When the scroll offset reached 200, the element will stick to the top of the browser window, because is placed as fixed.

Librettist answered 1/8, 2009 at 8:5 Comment(8)
that doesn't acchieve what I'm going for. I'd like the element to start at 200px below the top of the page (to allow room for other content) and then once the user has scrolled down become fixed at the top.Connivent
your edit does indeed fill the needs of the question now but you still have a problem when the page scrolls back to the top again. you could after reaching the element scrollTop store it somewhere, and when the page hits that position again (when scrolling upwards) change the css back to default... probably better to do this with a .toggleClass then...Isoagglutinin
This is pretty much what when with but I did have to remove the fixed positioning when the is window is scrolled back to the top. if ($(this).scrollTop() < 200 && $el.css('position') == 'fixed') { $('.fixedElement').css({'position': 'static', 'top': '0px'}); }Vernettaverneuil
@DerrickPetzold I put that into the answer, pretty important stuff :)Upstart
There is no need to set top for static positioned elementLouisalouisburg
the new example link you gave is so much clean and clear that I can't even see it! -_-Encephalograph
Thanks you for this code, But, when the div stick on the top, the width of div changes. Can we make it's width unchanged after sticky? Please helpUn
I added/removed a class instead of doing all that stuff inside the scroll event. The class CSS makes the think sticky.Houseraising
R
254

You've seen this example on Google Code's issue page and (only recently) on Stack Overflow's edit page.

CMS's answer doesn't revert the positioning when you scroll back up. Here's the shamelessly stolen code from Stack Overflow:

function moveScroller() {
    var $anchor = $("#scroller-anchor");
    var $scroller = $('#scroller');

    var move = function() {
        var st = $(window).scrollTop();
        var ot = $anchor.offset().top;
        if(st > ot) {
            $scroller.css({
                position: "fixed",
                top: "0px"
            });
        } else {
            $scroller.css({
                position: "relative",
                top: ""
            });
        }
    };
    $(window).scroll(move);
    move();
}
<div id="sidebar" style="width:270px;"> 
  <div id="scroller-anchor"></div> 
  <div id="scroller" style="margin-top:10px; width:270px"> 
    Scroller Scroller Scroller
  </div>
</div>

<script type="text/javascript"> 
  $(function() {
    moveScroller();
  });
</script> 

And a simple live demo.

A nascent, script-free alternative is position: sticky, which is supported in Chrome, Firefox, and Safari. See the article on HTML5Rocks and demo, and Mozilla docs.

Regent answered 28/1, 2010 at 10:30 Comment(9)
For some reason, the {scroll:false} was giving me issues (jQuery 1.6.2). Seems work without it. Fork from linked demo. Any idea if it serves a purpose?Acarology
I'm having alot of trouble with this, for the life of me I cannot replicate, i've even tried to replicate the live demo and its not working. can anyone link to a tutorial that provides step by step instructions?Counterman
This seems to work just fine, when I use the same version of jQuery as the demo (1.3.2). At some point offset must have stopped accepting an object as input api.jquery.com/offset. @Acarology Your modification should be safe with current jQuery.Myles
Is there any reason you couldn't replace var d = $("#scroller-anchor").offset().top; with var d = $("#sidebar").offset().top; and get rid of the empty scroller-anchor div all together? Here's my fork demonstrating what I'm talking about.Leboff
@MikeDeck I suspect that if there are margins or padding, you would like to be able to control where the scroller is positioned relative to the container.Regent
This script has some problems on browser like Safari Mobile, where the faster you scroll physically, the faster it goes. In this cases it takes some time before actually showing up.Moonlit
Could someone take a look at this: i am having trouble figuring it out: jsfiddle.net/Csf9SPerspiration
@Josh you can completely get rid of the condition if(st <= ot) {} since it's always true... I forked your fiddle: fiddle.jshell.net/34df1mj7/show/light If you agree I'd update your answerArgyres
Thanks you for this code, But, when the div stick on the top, the width of div changes. Can we make it's width unchanged after sticky? Please helpUn
C
163

As of January 2017 and the release of Chrome 56, most browsers in common use support the position: sticky property in CSS.

#thing_to_stick {
  position: sticky;
  top: 0;
}

does the trick for me in Firefox and Chrome.

In Safari you still need to use position: -webkit-sticky.

Polyfills are available for Internet Explorer and Edge; https://github.com/wilddeer/stickyfill seems to be a good one.

Ce answered 23/1, 2017 at 13:46 Comment(3)
This is supported in most browsers in common use today. See caniuse.com/#feat=css-sticky Secondly, I much prefer a solution which can be boiled down to 2 lines of code to a version that requires custom Javascript. And it's future-proof too. Use a polyfill if you're worried about browser compatibility.Arrowwood
I will like to add to this comment that we can z-index: 99999;, because if not when it goes to top, the other content will be rendered first. But this should be the accepted solution.Haaf
Just wrap it in a div with id="thing_to_stick"Seema
J
36

And here's how without jquery (UPDATE: see other answers where you can now do this with CSS only)

var startProductBarPos=-1;
window.onscroll=function(){
  var bar = document.getElementById('nav');
  if(startProductBarPos<0)startProductBarPos=findPosY(bar);

  if(pageYOffset>startProductBarPos){
    bar.style.position='fixed';
    bar.style.top=0;
  }else{
    bar.style.position='relative';
  }

};

function findPosY(obj) {
  var curtop = 0;
  if (typeof (obj.offsetParent) != 'undefined' && obj.offsetParent) {
    while (obj.offsetParent) {
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
    }
    curtop += obj.offsetTop;
  }
  else if (obj.y)
    curtop += obj.y;
  return curtop;
}
* {margin:0;padding:0;}
.nav {
  border: 1px red dashed;
  background: #00ffff;
  text-align:center;
  padding: 21px 0;

  margin: 0 auto;
  z-index:10; 
  width:100%;
  left:0;
  right:0;
}

.header {
  text-align:center;
  padding: 65px 0;
  border: 1px red dashed;
}

.content {
  padding: 500px 0;
  text-align:center;
  border: 1px red dashed;
}
.footer {
  padding: 100px 0;
  text-align:center;
  background: #777;
  border: 1px red dashed;
}
<header class="header">This is a Header</header>
<div id="nav" class="nav">Main Navigation</div>
<div class="content">Hello World!</div>
<footer class="footer">This is a Footer</footer>
Jab answered 5/7, 2013 at 18:29 Comment(6)
Thank you! Getting hard to find native JS solutions these days. This worked perfectly.Gruesome
Thank you so much, this worked perfectly since jquery was conflicting with some legacy enterprise code my project hasIvetteivetts
though im running into a problem where if I scroll to the bottom of the page it will automatically pop me back up to the top.Ivetteivetts
@Ivetteivetts Does my sample page do that?Jab
@JimW I found out the issue. I was trying to use it with a vertical based menu bar next to a main content div to the left. It was bugging out when you scroll down since it can't determine when it's hitting the bottom of the page properly. I ended up adding a line of code to set the container div height to the window screen size to the scroll event listenerIvetteivetts
There is an issue with this solution because the content "jumps" up. It's easier to see it with smaller padding-top. Demo: jsbin.com/fivugux/edit?html,css,js,outputDelgadillo
V
33

I had the same problem as you and ended up making a jQuery plugin to take care of it. It actually solves all the problems people have listed here, plus it adds a couple of optional features too.

Options

stickyPanelSettings = {
    // Use this to set the top margin of the detached panel.
    topPadding: 0,

    // This class is applied when the panel detaches.
    afterDetachCSSClass: "",

    // When set to true the space where the panel was is kept open.
    savePanelSpace: false,

    // Event fires when panel is detached
    // function(detachedPanel, panelSpacer){....}
    onDetached: null,

    // Event fires when panel is reattached
    // function(detachedPanel){....}
    onReAttached: null,

    // Set this using any valid jquery selector to 
    // set the parent of the sticky panel.
    // If set to null then the window object will be used.
    parentSelector: null
};

https://github.com/donnyv/sticky-panel

demo: http://htmlpreview.github.io/?https://github.com/donnyv/sticky-panel/blob/master/jquery.stickyPanel/Main.htm

Versatile answered 19/1, 2011 at 20:9 Comment(6)
Hey! Thank you! This is a great solution, and thanks for sharing, for sure it saved me a lot of time. This should be the overall accepted solution for this question, since as far as I have read, it is the most complete solution. Basically, the others did not solve the problem with the original X-position of a block after the position: fixed style is applied. Yours solves this problem. Really, many thanks!Sloe
Hey Donny, also love your plugin (v1.4.1)... did come across one issue, Block elelments lost their width if none was specified. So altered it when detaching... only by setting the width so it remains the same. code// detach panel node.css({ "margin": 0, "left": nodeLeft, "top": newNodeTop, "position": "fixed", "width": node.width() });codePara
Looked for and tried many solutions, and this worked "right out of the box." Amazing work! Thank you!Smelly
@WillHancock I'v added iPad support, fixed the refresh bug and added onDetached & onReattached events. The new events will give you access to the panel & spacerpanel after it has detached & reattached.Versatile
Also added a parentSelector option to support scrolling divs.Versatile
It only remains sticky as long as its container is in the window when the container gets scrolled up,Ridgeway
G
21

The simplest solution (without js) : demo

.container {
  position: relative;
}
.sticky-div {
    position: sticky;
    top: 0;
}
<div class="container">
  <h1>
    relative container & sticky div
  </h1>
  <div class="sticky-div"> this row is sticky</div>
  <div>
    content
  </div>
</div>
Gamali answered 18/1, 2022 at 16:15 Comment(1)
No need position: relativeDelgadillo
F
11

This is how i did it with jquery. This was all cobbled together from various answers on stack overflow. This solution caches the selectors for faster performance and also solves the "jumping" issue when the sticky div becomes sticky.

Check it out on jsfiddle: http://jsfiddle.net/HQS8s/

CSS:

.stick {
    position: fixed;
    top: 0;
}

JS:

$(document).ready(function() {
    // Cache selectors for faster performance.
    var $window = $(window),
        $mainMenuBar = $('#mainMenuBar'),
        $mainMenuBarAnchor = $('#mainMenuBarAnchor');

    // Run this on scroll events.
    $window.scroll(function() {
        var window_top = $window.scrollTop();
        var div_top = $mainMenuBarAnchor.offset().top;
        if (window_top > div_top) {
            // Make the div sticky.
            $mainMenuBar.addClass('stick');
            $mainMenuBarAnchor.height($mainMenuBar.height());
        }
        else {
            // Unstick the div.
            $mainMenuBar.removeClass('stick');
            $mainMenuBarAnchor.height(0);
        }
    });
});
Forethought answered 26/3, 2013 at 0:44 Comment(0)
C
10

As Josh Lee and Colin 't Hart have said, you could optionally just use position: sticky; top: 0; applying to the div that you want the scrolling at...

Plus, the only thing you will have to do is copy this into the top of your page or format it to fit into an external CSS sheet:

<style>
#sticky_div's_name_here { position: sticky; top: 0; }
</style>

Just replace #sticky_div's_name_here with the name of your div, i.e. if your div was <div id="example"> you would put #example { position: sticky; top: 0; }.

Crackbrain answered 27/6, 2017 at 14:21 Comment(0)
X
7

Here is another option:

JAVASCRIPT

var initTopPosition= $('#myElementToStick').offset().top;   
$(window).scroll(function(){
    if($(window).scrollTop() > initTopPosition)
        $('#myElementToStick').css({'position':'fixed','top':'0px'});
    else
        $('#myElementToStick').css({'position':'absolute','top':initTopPosition+'px'});
});

Your #myElementToStick should start with position:absolute CSS property.

Xenomorphic answered 12/9, 2013 at 22:17 Comment(1)
I think this is a very clean and easy solution. I just would not position the element "absolute" - this might break the layout - I would just set it to static.Pemphigus
H
2

Here's one more version to try for those having issues with the others. It pulls together the techniques discussed in this duplicate question, and generates the required helper DIVs dynamically so no extra HTML is required.

CSS:

.sticky { position:fixed; top:0; }

JQuery:

function make_sticky(id) {
    var e = $(id);
    var w = $(window);
    $('<div/>').insertBefore(id);
    $('<div/>').hide().css('height',e.outerHeight()).insertAfter(id);
    var n = e.next();
    var p = e.prev();
    function sticky_relocate() {
      var window_top = w.scrollTop();
      var div_top = p.offset().top;
      if (window_top > div_top) {
        e.addClass('sticky');
        n.show();
      } else {
        e.removeClass('sticky');
        n.hide();
      }
    }
    w.scroll(sticky_relocate);
    sticky_relocate();
}

To make an element sticky, do:

make_sticky('#sticky-elem-id');

When the element becomes sticky, the code manages the position of the remaining content to keep it from jumping into the gap left by the sticky element. It also returns the sticky element to its original non-sticky position when scrolling back above it.

Heathheathberry answered 5/8, 2013 at 21:0 Comment(1)
Your approach is very similar to JohnB's approach. Considering your differences to that answer, I'm wondering (1) Is there an advantage to using a second "helper div" (instead of just 1 like JohnB uses), and (2) Is there an advantage to using hide() and show() instead of just setting the helper div's height (like JohnB does)? Perhaps a performance difference? So far I haven't been able to discern differences but perhaps certain scenarios would have differences (like maybe involving inline elements or something), so that's why I ask. Thanks.Carriole
P
1

My solution is a little verbose, but it handles variable positioning from the left edge for centered layouts.

// Ensurs that a element (usually a div) stays on the screen
//   aElementToStick   = The jQuery selector for the element to keep visible
global.makeSticky = function (aElementToStick) {
    var $elementToStick = $(aElementToStick);
    var top = $elementToStick.offset().top;
    var origPosition = $elementToStick.css('position');

    function positionFloater(a$Win) {
        // Set the original position to allow the browser to adjust the horizontal position
        $elementToStick.css('position', origPosition);

        // Test how far down the page is scrolled
        var scrollTop = a$Win.scrollTop();
        // If the page is scrolled passed the top of the element make it stick to the top of the screen
        if (top < scrollTop) {
            // Get the horizontal position
            var left = $elementToStick.offset().left;
            // Set the positioning as fixed to hold it's position
            $elementToStick.css('position', 'fixed');
            // Reuse the horizontal positioning
            $elementToStick.css('left', left);
            // Hold the element at the top of the screen
            $elementToStick.css('top', 0);
        }
    }

    // Perform initial positioning
    positionFloater($(window));

    // Reposition when the window resizes
    $(window).resize(function (e) {
        positionFloater($(this));
    });

    // Reposition when the window scrolls
    $(window).scroll(function (e) {
        positionFloater($(this));
    });
};
Piste answered 15/11, 2012 at 22:34 Comment(0)
W
1

Here is an extended version to Josh Lee's answer. If you want the div to be on sidebar to the right, and float within a range (i.e., you need to specify top and bottom anchor positions). It also fixes a bug when you view this on mobile devices (you need to check left scroll position otherwise the div will move off screen).

function moveScroller() {
    var move = function() {
        var st = $(window).scrollTop();
        var sl = $(window).scrollLeft();
        var ot = $("#scroller-anchor-top").offset().top;
        var ol = $("#scroller-anchor-top").offset().left;
        var bt = $("#scroller-anchor-bottom").offset().top;
        var s = $("#scroller");
        if(st > ot) {
            if (st < bt - 280) //280px is the approx. height for the sticky div
            {
                s.css({
                    position: "fixed",
                    top: "0px",
                    left: ol-sl
                }); 
            }
            else
            {
                s.css({
                    position: "fixed",
                    top: bt-st-280,
                    left: ol-sl
                }); 
            }
        } else {
            s.css({
                position: "relative",
                top: "",
                left: ""
            });

        }
    };
    $(window).scroll(move);
    move();
}
Wiser answered 23/12, 2013 at 3:3 Comment(0)
R
1

I came across this when searching for the same thing. I know it's an old question but I thought I'd offer a more recent answer.

Scrollorama has a 'pin it' feature which is just what I was looking for.

http://johnpolacek.github.io/scrollorama/

Randallrandan answered 14/4, 2015 at 7:24 Comment(0)
H
1

You can make it without using javascript by using :

.element_to_stick {
  position: sticky;
  top: 0px; // Top calculated from div Parent, not top screen !
}

In Safari you still need to use position: -webkit-sticky.

Horseshoes answered 9/5, 2023 at 20:13 Comment(0)
C
0

The info provided to answer this other question may be of help to you, Evan:

Check if element is visible after scrolling

You basically want to modify the style of the element to set it to fixed only after having verified that the document.body.scrollTop value is equal to or greater than the top of your element.

Cimbalom answered 1/8, 2009 at 8:13 Comment(0)
E
0

The accepted answer works but doesn't move back to previous position if you scroll above it. It is always stuck to the top after being placed there.

  $(window).scroll(function(e) {
    $el = $('.fixedElement');
    if ($(this).scrollTop() > 42 && $el.css('position') != 'fixed') {
      $('.fixedElement').css( 'position': 'fixed', 'top': '0px');

    } else if ($(this).scrollTop() < 42 && $el.css('position') != 'relative') {
      $('.fixedElement').css( 'relative': 'fixed', 'top': '42px');
//this was just my previous position/formating
    }
  });

jleedev's response whould work, but I wasn't able to get it to work. His example page also didn't work (for me).

Encratia answered 8/7, 2010 at 14:29 Comment(0)
L
0

You can add 3 extra rows so when the user scroll back to the top, the div will stick on its old place:

Here is the code:

if ($(this).scrollTop() < 200 && $el.css('position') == 'fixed'){
    $('.fixedElement').css({'position': 'relative', 'top': '200px'});
}
Liggitt answered 2/10, 2010 at 11:31 Comment(0)
M
0

I have links setup in a div so it is a vertical list of letter and number links.

#links {
    float:left;
    font-size:9pt;
    margin-left:0.5em;
    margin-right:1em;
    position:fixed;
    text-align:center;
    width:0.8em;
}

I then setup this handy jQuery function to save the loaded position and then change the position to fixed when scrolling beyond that position.

NOTE: this only works if the links are visible on page load!!

var listposition=false;
jQuery(function(){
     try{
        ///// stick the list links to top of page when scrolling
        listposition = jQuery('#links').css({'position': 'static', 'top': '0px'}).position();
        console.log(listposition);
        $(window).scroll(function(e){
            $top = $(this).scrollTop();
            $el = jQuery('#links');
            //if(typeof(console)!='undefined'){
            //    console.log(listposition.top,$top);
            //}
            if ($top > listposition.top && $el.css('position') != 'fixed'){
                $el.css({'position': 'fixed', 'top': '0px'});
            }
            else if ($top < listposition.top && $el.css('position') == 'fixed'){
                $el.css({'position': 'static'});
            }
        });

    } catch(e) {
        alert('Please vendor [email protected] (Myvendor JavaScript Issue)');
    }
});
Malapert answered 11/11, 2010 at 13:58 Comment(0)
V
0

I used some of the work above to create this tech. I improved it a bit and thought I would share my work. Hope this helps.

jsfiddle Code

function scrollErrorMessageToTop() {
    var flash_error = jQuery('#flash_error');
    var flash_position = flash_error.position();

    function lockErrorMessageToTop() {
        var place_holder = jQuery("#place_holder");
        if (jQuery(this).scrollTop() > flash_position.top && flash_error.attr("position") != "fixed") {
            flash_error.css({
                'position': 'fixed',
                'top': "0px",
                "width": flash_error.width(),
                "z-index": "1"
            });
            place_holder.css("display", "");
        } else {
            flash_error.css('position', '');
            place_holder.css("display", "none");
        }

    }
    if (flash_error.length > 0) {
        lockErrorMessageToTop();

        jQuery("#flash_error").after(jQuery("<div id='place_holder'>"));
        var place_holder = jQuery("#place_holder");
        place_holder.css({
            "height": flash_error.height(),
            "display": "none"
        });
        jQuery(window).scroll(function(e) {
            lockErrorMessageToTop();
        });
    }
}
scrollErrorMessageToTop();​

This is a little bit more dynamic of a way to do the scroll. It does need some work and I will at some point turn this into a pluging but but this is what I came up with after hour of work.

Vesicatory answered 28/11, 2012 at 22:59 Comment(0)
S
0

In javascript you can do:

var element = document.getElementById("myid");
element.style.position = "fixed";
element.style.top = "0%";
Spritsail answered 29/5, 2013 at 22:55 Comment(0)
B
0

Here's an example that uses jquery-visible plugin: http://jsfiddle.net/711p4em4/.

HTML:

<div class = "wrapper">
    <header>Header</header>
    <main>
        <nav>Stick to top</nav>
        Content
    </main>
    <footer>Footer</footer>
</div>

CSS:

* {
    margin: 0;
    padding: 0;
}

body {
    background-color: #e2e2e2;
}

.wrapper > header,
.wrapper > footer {
    font: 20px/2 Sans-Serif;
    text-align: center;
    background-color: #0040FF;
    color: #fff;
}

.wrapper > main {
    position: relative;
    height: 500px;
    background-color: #5e5e5e;
    font: 20px/500px Sans-Serif;
    color: #fff;
    text-align: center;
    padding-top: 40px;
}

.wrapper > main > nav {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    font: 20px/2 Sans-Serif;
    color: #fff;
    text-align: center;
    background-color: #FFBF00;
}

.wrapper > main > nav.fixed {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
}

JS (include jquery-visible plugin):

(function($){

    /**
     * Copyright 2012, Digital Fusion
     * Licensed under the MIT license.
     * http://teamdf.com/jquery-plugins/license/
     *
     * @author Sam Sehnert
     * @desc A small plugin that checks whether elements are within
     *       the user visible viewport of a web browser.
     *       only accounts for vertical position, not horizontal.
     */
    var $w = $(window);
    $.fn.visible = function(partial,hidden,direction){

        if (this.length < 1)
            return;

        var $t        = this.length > 1 ? this.eq(0) : this,
            t         = $t.get(0),
            vpWidth   = $w.width(),
            vpHeight  = $w.height(),
            direction = (direction) ? direction : 'both',
            clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;

        if (typeof t.getBoundingClientRect === 'function'){

            // Use this native browser method, if available.
            var rec = t.getBoundingClientRect(),
                tViz = rec.top    >= 0 && rec.top    <  vpHeight,
                bViz = rec.bottom >  0 && rec.bottom <= vpHeight,
                lViz = rec.left   >= 0 && rec.left   <  vpWidth,
                rViz = rec.right  >  0 && rec.right  <= vpWidth,
                vVisible   = partial ? tViz || bViz : tViz && bViz,
                hVisible   = partial ? lViz || rViz : lViz && rViz;

            if(direction === 'both')
                return clientSize && vVisible && hVisible;
            else if(direction === 'vertical')
                return clientSize && vVisible;
            else if(direction === 'horizontal')
                return clientSize && hVisible;
        } else {

            var viewTop         = $w.scrollTop(),
                viewBottom      = viewTop + vpHeight,
                viewLeft        = $w.scrollLeft(),
                viewRight       = viewLeft + vpWidth,
                offset          = $t.offset(),
                _top            = offset.top,
                _bottom         = _top + $t.height(),
                _left           = offset.left,
                _right          = _left + $t.width(),
                compareTop      = partial === true ? _bottom : _top,
                compareBottom   = partial === true ? _top : _bottom,
                compareLeft     = partial === true ? _right : _left,
                compareRight    = partial === true ? _left : _right;

            if(direction === 'both')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
            else if(direction === 'vertical')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
            else if(direction === 'horizontal')
                return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        }
    };

})(jQuery);

$(function() {
    $(window).scroll(function() {
        $(".wrapper > header").visible(true) ?
            $(".wrapper > main > nav").removeClass("fixed") :
            $(".wrapper > main > nav").addClass("fixed");
    });
});
Bimetallism answered 29/10, 2014 at 22:31 Comment(0)
R
0

I had a similar problem - I had a div that was already floating in 'fixed' position above other content, defined by CSS. What I wanted to achieve was when I scrolled the page down, the div would start scrolling down with content but then stick to the top of the page (i.e. would never disappear).

The style of my div is:

.inProjectNavigation {
  width: 60.5%;
  max-width: 1300px;
  position: fixed; top: 60%;
  display: block;
}

I simply put this div somewhere on the page and it appears on top of content. There are no special requirements for the style of its parents.

The the JS to make it stick to the top is:

const MIN_TOP_POSITION = 30;

/**
 * Make the project navigation initially scroll down with the page, but then stick to the top of the browser
 */
$(window).scroll(function(e){ 
  let $navigationDiv = $('.inProjectNavigation');
  let originalTopPosPx = $navigationDiv.attr('data-originalTopPosPx');
  //-- on first scroll, save the original px position in the element, as defined by CSS
  if (originalTopPosPx == null) {
    let cssValue = $navigationDiv.css('top');
    originalTopPosPx = cssValue.substring(0, cssValue.length - 2); // get rid of the 'px'
    $navigationDiv.attr('data-originalTopPosPx', originalTopPosPx); 
  }
  //-- follow the scroll, but stick to top
  $navigationDiv.css({'top': Math.max(MIN_TOP_POSITION, (originalTopPosPx - $(this).scrollTop())) + 'px'});
});

Tested on a Mac - Safari, Firefox, Chrome. Hopefully should work in IE too :)

Rahmann answered 15/3, 2023 at 23:1 Comment(0)
E
0

To stick anything to the top of the screen, position: sticky; won't work. I am experiencing the same situation with a sidebar, and I was able to stick it with position: fixed;.

Here is my whole website:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html><head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta charset="UTF-8">
        <title>Events Beta</title>
        <style>
          /* COMMON */
body {
    font-family: 'Segoe UI', sans-serif;
    margin: 0px;
    width: 100%;
    height: 100%;
}
a, button {
    margin: 8px;
    padding: 10px;
    border-radius: 8px;
    background-color: #0d6efd;
    border: 1px solid #fff;
    color: #fff;
    text-decoration: none;
    transition: background-color 0.9s;
    display: inline-flex;
}
.secondary {
    background-color: #ffffff00;
    color: #ccc;
    float: right;
    border: 2px solid #ccc;
}
a:hover, button:hover {
    background-color: #5398fe;
}
h1, h2, h3 {
    font-weight: 600;
}
dialog {
    border-radius: 6px;
}
header {
    background-color: #212020;
    margin: 0px; 
    padding: 15px; 
    color: #ffffff;
    height: 32px;
}
header img {
    width: auto;
    height: 32px;
}
select {
    padding: 10px;
    border-radius: 5px;
    background-color: rgb(248, 249, 250);;
    color: rgb(33, 37, 41);
}
.object {
    background-color: #ccc;
    border-radius: 6px;
    padding: 8px;
    margin: 8px;
    width: 40%;
    display: inline-block;
    vertical-align: top;
}
input, textarea {
    padding: 10px;
    border: 1px solid rgb(222, 226, 230);
    background-color: rgb(248, 249, 250);
    color: rgb(33, 37, 41);
    border-radius: 5px;
}
footer {
    padding: 15px;
    background-color: rgb(248, 249, 250);
    color: #0d6efd;
}
footer a {
    color: inherit;
    text-decoration: none;
    background-color: #ffffff00;
    border: none;

}
a.secondary {
    float: right;
    background-color: #ffffff00;
    color: #000;
}
.clear {
    clear: both;
}
.island {
    text-align: center;
    border: 2px solid #ccc;
    width: fit-content;
    border-radius: 6px;
    margin: auto;
    padding: 10px;
    margin-top: 10px;
}
.exclusive {
    display: none;
}
/* NAV */
.top_menu nav {
    float: right;
}
.top_menu nav a {
    font-weight: 600;
    padding-left: 20px;
    color: #ffffff;
    text-decoration: none;
    background-color: #ffffff00;
    border: none;
    display: inline;
}
.top_menu nav a:first-child {
    padding-left: 0px;
}

/* FORM COMMON */
.form-inline {
    margin: 15px 0px;
    max-width: 330px;
    background-color: #f5f5f5;
    border-radius: 5px;
    padding: 15px;
}
.form-inline label {
    width: 100px;
    display: block;
    float: left;
    margin-top: 10px;
}
.form-inline input, 
.form-inline textarea, 
.form-inline select {
    margin-bottom: 5px;
    width: 200px;
}
.form-inline input[type="checkbox"] {
    margin-top: 15px;
}
.form-inline input::after, 
.form-inline textarea::after, 
.form-inline select::after,
.form-inline input[type="checkbox"]::after {
    content: " ";
    clear: both;
}

/* BLOG */
.blog-post {
    padding: 15px 0px 18px 0px;
    border-bottom: 2px dotted #ccc;
    clear: both;
}
.blog-post:last-child {
    border-bottom: 0px;
}
.blog-date {
    float: right;
    color: #9f9f9f;
}
.blog-post h3.blog-title {
    margin: 0px 0px 10px 0px;
    padding: 5px 10px;
    background-color: #7250ef;
    color: #fff;
    display: inline-block;
    border-radius: 3px;
}
.blog-categories {
    font-weight: 600;
    color: #adabf4;
    font-size: 14px;
    padding-top: 10px;
}
.blog-content {
    font-size: 17px;
}
.container

/* EVENTS */
.inline-text {
    width: 300px;
}

/* Sidebar CSS */


html, body {
    height: 100%;

    }
    body {
    margin: 0;
    padding: 0;
    }
    /* Let's style our sidebar */
    .sidebar {
    width: 30%;
    background-color: #333;
    color: white;
    position: absolute;
    overflow-x: hidden;
    overflow-y: auto;
    height: 100%;
    }
    .sidebar > div {
    padding: 1px 20px 20px 20px;
    }
    .sidebar ul {
    padding-left: 0px;
    }
    .sidebar li {
    list-style-type: none;
    }
    .sidebar li a {
    color: inherit;
    text-decoration: none;
    border-radius: 4px;
    padding: 8px;
    margin: 0px -8px;
    display: block;
    background-color: #ffffff00;
    }
    .sidebar li a.active,
    .sidebar li a.active:hover {
    background-color: #666;
    }
    .sidebar li a:hover {
    background-color: #444;
    }
    /* Some styling for the main content area */
    .container { 
        margin-left: 250px;    /* Leave space for the sidebar */
        overflow-x: hidden;
        overflow-y: auto;
        height: 80%;
        width: 70%;
    }
    .container .page {
        padding: 20px;
        height: 100%;
        display: none;
        padding-bottom: 0px;
        padding-right: 0px;

    }
    .container .page.display {
        display: block;
    }


/* Media Queries */
@media (max-width: 700px) {
    .container {
        margin-left: 0px !important;
        width: 100% !important;
    }
    .sidebar {
        float: none !important;
        text-align: center !important;
        height: fit-content !important;
        width: 100% !important;
        position: sticky !important;
        top: 0px;
    }
    .sidebar a {
        width: fit-content;
    }
    #mobile-nav {
        display: inline;
    }
    #desk-nav {
        display: none;
    }
    .object {
        width: 90%;
    }
}
@media (min-width: 700px) {
    .sidebar {
        width: 230px !important;
        padding: 15px;
    }
    #desk-nav {
        display: inline;
    }
    #mobile-nav {
        display: none;
    }
} 

        </style>
        <link rel="icon" href="logo_white.png" type="image/png">
        <script src="script.js"></script>
        <script>
            function auth() {
                var good = document.cookie.indexOf('authToken');
                var createButton = document.querySelector("button#create_event.exclusive");
                if (good = true) {
                    document.querySelector("button#create_event.exclusive").style.display = "inline-flex";
                    
                }
                function redirect() {
                    createButton.addEventListener('click', redirect);
                }
            }
            var head = document.querySelector("header.top_menu");
            var body = document.querySelector("div.container");
            body.width = head.width;
            
            
            
            
            auth();
        </script>
    </head>
    <body>
        <header class="top_menu">
            <img id="logo" src="logo_white.png">
            <nav>
                <button onclick="talDialogOpen()">Projects</button>
                <dialog id="tal">
                    <button onclick="talDialogClose()" class="secondary">Close</button>
                    <h3>Projects</h3>
                    <small>This is a list of my projects. You can see my GitHub for more.</small>
                    <div class="object">
                        <h3>The Agent: Legacy</h3>
                        <p>A game about how an FBI agent uncovers a scheme to steal the plans for a military drug that is much bigger than himself
                        <br>
                        This game is being made in Unreal Engine 5.2, but may be moved to CryENGINE due to fees.
                        <br>
                        Platforms: Mainly PC but all</p>
                    </div>
                </dialog>
                <dialog id="events">
                    <button onclick="evDialogClose()" class="secondary">Close</button>
                    <h3>Events</h3>
                    <div class="object">
                        There are no events right now.
                    </div>
                    <a href="events.php"><button class="exclusive" id="create_event">Create Event</button></a>
                </dialog>

                <button onclick="evDialogOpen()">Events</button>

                <script>
                    function evDialogOpen() {
                        document.getElementById("events").open = true;
                    }
                    function evDialogClose() {
                        document.getElementById("events").close();
                    }
                </script>
                <script>
                    // Script to handle dialogs
                    function talDialogOpen() {
                        document.getElementById("tal").open = true;
                    }
                    function talDialogClose() {
                        document.getElementById("tal").close();
                    }
                </script>
            </nav>
                <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
                <script>
                    
                    // define a default navigation starting point (usually first link on sidebar nav)
                    var default_nav_hash = "#home";
                    
                    // handle sidebar navigation hash for "initial load of page"
                    function nav_hash() {
                    
                    // make sure its a string and the length is larger than a '#' value
                    if (window.location.hash.length <= 1) {
                        // set the default hash in the URL
                        window.location.hash = default_nav_hash;
                    }

                    // set it as .active (default was set above if there was none)
                    $('.sidebar a[href="' + window.location.hash + '"]').addClass('active');
                    $('#' + window.location.hash.substring(1) + '.page').addClass('display');

                    }

                    // once the document is ready (DOM - Document Object Model)
                    $(document).ready(function() {

                    // process initial load of page
                    nav_hash();
                    
                    // process based on click
                    $('.sidebar a').click(function() {
                        
                        // clear .active from all
                        $('.sidebar a').removeClass('active');
                        $('.page').removeClass('display');
                        
                        // set THIS to active (its been clicked on)
                        $(this).addClass('active');
                        $('#' + $(this).attr('href').substring(1) + '.page').addClass('display');

                    });

                    });

                </script>
                <style>
                    html, body {
                    height: 100%;

                    }
                    body {
                    margin: 0;
                    padding: 0;
                    }
                    /* Let's style our sidebar */
                    .sidebar {
                    width: 30%;
                    background-color: #333;
                    color: white;
                    position: absolute;
                    overflow-x: hidden;
                    overflow-y: auto;
                    height: 100%;
                    }
                    .sidebar > div {
                    padding: 1px 20px 20px 20px;
                    }
                    .sidebar ul {
                    padding-left: 0px;
                    }
                    .sidebar li {
                    list-style-type: none;
                    }
                    .sidebar li a {
                    color: inherit;
                    text-decoration: none;
                    border-radius: 4px;
                    padding: 8px;
                    margin: 0px -8px;
                    display: block;
                    }
                    .sidebar li a.active,
                    .sidebar li a.active:hover {
                    background-color: #666;
                    }
                    .sidebar li a:hover {
                    background-color: #444;
                    }
                    /* Some styling for the main content area */
                    .container { 
                        margin-left: 250px;    /* Leave space for the sidebar */
                        overflow-x: hidden;
                        overflow-y: auto;
                        height: 100%;
                        width: 70%;
                    }
                    .container .page {
                        padding: 20px;
                        height: 100%;
                        display: none; /* treat as page pages */

                    }
                    .container .page.display {
                        display: block;
                    }
                </style>
                
                

                <!-- Sidebar -->
                
            
        </header>
        <section>

<nav>
    <div class="sidebar">
        <div id="mobile-nav">
            <a href="#home">Home</a>
            <a href="#portfolio">Info</a>
            <a href="#contact">FBLA</a>
            <a href="#classes">Schedule</a>
            <a href="#guides" class="active">Events</a>
        </div>
        <div id="desk-nav">
            <h2>Pages</h2>
            <li><a href="#home">Home</a></li>
            <li><a href="#portfolio">Info</a></li>
            <li><a href="#contact">FBLA</a></li>
            <li><a href="#classes">Schedule</a></li>
            <li><a href="#guides" class="active">Events</a></li>
        </div>
    </div>
</nav>

  <!-- Each Div element in here counts as a section that won't display unless it is selected on the sidebar. The code in in header.php -->
  <div class="container">
    
    <div class="page" id="home">
        <h1>Hello, User!</h1>
        <p>
            Welcome to the website for Events Beta! This will be used for purposes like sharing info. 
            <br>
            Visit the other tabs on the left (or top if your on a phone), and explore.
            <br>
            Here is an app list so you can go places fast:
            </p><ul>
                <li><a href="https://mail.google.com" target="_blank">Gmail</a></li>
                <li><a href="https://mail.google.com/chat" target="_blank">Google Chat</a></li>
                <li><a href="https://www.github.com/realitygamesdev" target="_blank">GitHub</a></li>
                <li><a href="mailto:****************@gmail.com" target="_blank">Email me</a><small>This may not work, as the browser cannot open emails and you need to have an email client like Outlook installed on your device.</small></li>
            </ul>
        <p></p>
    </div>

    <div class="page" id="portfolio">
        <h1>Info</h1>
        <p>This is my and any mutual info that should be listed on this website.</p>
        <ul>
            <li>School: Osceola Creek Middle School</li>
            <li>Email: *******************@gmail.com <a href="https://mail.google.com">Open Gmail</a></li>
            <li>To chat with me and my friends, go to <a href="https://chat.google.com">Google Chat</a> and enter my email.</li>
        </ul>
        <p>You may also need my interests. Here they are.</p>
        <ul>
            <li>Coding</li>
            <li>Making Video Games</li>
            <li>Playing Video Games</li>
            <li>Working with media (videos, images, etc.)</li>
            <li>Anything on the computer</li>
        </ul>
    </div>

    <div class="page" id="classes">
        <h1>Classes</h1>
        <p>These are my daily classes in school, and their info.</p>
        <p>My daily periods</p>
        <>
            
        </>
    </div>

    <div class="page" id="contact">
        <h1>FBLA Projects</h1>
        <p>I am in FBLA, and have competitions all the time. The projects for them are in here.</p>
        <div class="object">
            <h2>Video Game Challenge</h2>
            <p>
                The challenge for this is to make a semi complicated video game to present to the judges.
                <br>
                The game is planned to be 3D, but may be 2D due to a lack of avalible resources. 
                <br>
                If it's 3D, it will be made in CryENGINE due to fees with Unreal Engine.
            </p>
        </div>
    </div>

        <div class="page display" id="guides">
            <h2>Events</h2>
            <p>Welcome to Events Beta. This is your console for seeing and participating in events.</p>

            <div class="object">
                <h3>Events</h3>
                <p>This module is in PHP</p>

    
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>Loading</title>
        <script>
            
        </script>
    
    
        <div style="text-align: center;">
            <video src="loading.mp4" loop="" autoplay="" muted="" width="50px"></video>
            <noscript>
                <div style="background-color: red;color:white;width:fit-content;border-radius:6px;padding:10px;margin-left:40%;">
                    This site uses JavaScript to function correctly.
                    <br>
                    You would normally see content here, but you must enable JavaScript first.
                </div>
            </noscript>
        </div>
    
                <h3>Event: Chat with Caleb</h3><p>Date: 10/20/2023</p><p>Participants: Gabriel, Caleb</p><h3>Event: </h3><p>Date: </p><p>Participants: </p>            </div>


            <div class="object">
                <h3>Add an event</h3>
                <p>Use the form below to add an event that others can participate in.</p>
                <form action="api.php" method="post">
                <label for="event_name">Event Name:</label>
                <input type="text" id="event_name" name="event_name" required="">
                <br>
                <label for="event_date">Event Date:</label>
                <input type="date" id="event_date" name="event_date" required="">
                <br>
                <label for="event_participants">Participants (comma-separated):</label>
                <input type="text" id="event_participants" name="event_participants">
                <br>
                <button type="submit">Add Event</button>
                </form>
            </div>

            <h2>Developers</h2>
            <p>This section is for developers (or me) who want to use my API.</p>

            <div class="object">
                <h3>Import the API</h3>
                <p>To import the API, link https://gabriel.jemail.us/api.js</p>
                <p>This is a JavaScript API. <b>It is not compatible with Python.</b></p>
            </div>

            <div class="object">
                <h3>API Reference</h3>
                <p>
                To see documentation for the API, click the button.
                <a href="docs.txt" download="">See docs</a>
                </p>
            </div>
            </div>
        
    </div>

  






</section>



    </body></html>

IF YOUR SCREEN IN SMALLER THAN 700PX, THE NAVBAR WILL NOT STICK. DO NOT OPEN DIALOGS, AS THAT IS UNDER DEVELOPMENT

That is the code for my website. It works in Chrome fine, but please test it. This was my solution, it should be fine for others.

Estaminet answered 21/10, 2023 at 19:35 Comment(1)
The previous solution from @Spritsail can also be done, but it is risky. JavaScript can fail due to integration with CSS issues.Estaminet
P
-1

Not an exact solution but a great alternative to consider

this CSS ONLY Top of screen scroll bar. Solved all the problem with ONLY CSS, NO JavaScript, NO JQuery, No Brain work (lol).

Enjoy my fiddle :D all the codes are included in there :)

CSS

#menu {
position: fixed;
height: 60px;
width: 100%;
top: 0;
left: 0;
border-top: 5px solid #a1cb2f;
background: #fff;
-moz-box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.16);
-webkit-box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.16);
box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.16);
z-index: 999999;
}

.w {
    width: 900px;
    margin: 0 auto;
    margin-bottom: 40px;
}<br type="_moz">

Put the content long enough so you can see the effect here :) Oh, and the reference is in there as well, for the fact he deserve his credit

CSS ONLY Top of screen scroll bar

Praiseworthy answered 5/9, 2013 at 14:12 Comment(5)
A little bit offtopic ;)Pemba
I am not against a good solution, but the code in your answer provides a way to make something like a menu to always stick on top. But that was not the question...Pemba
you are just fixing the div and not doing anything sticky on scrolling.Indemnity
As other's have pointed out, this doesn't make an element sticky on scroll, it's just always fixed to the top of the screen which of course can easily be done in css. It's the process of determing the scroll amount and then changing position: absolute -> fixed and removing it again that needs solvingDeanedeaner
no, no, no ... it is not what the OP asked. He want his element to scroll and stay sticky once it reached the top.Shishko
G
-1

sticky till the footer hits the div:

function stickyCostSummary() {
    var stickySummary = $('.sticky-cost-summary');
    var scrollCostSummaryDivPosition = $(window).scrollTop();
    var footerHeight = $('#footer').height();
    var documentHeight = $(document).height();
    var costSummaryHeight = stickySummary.height();
    var headerHeight = 83;
    var footerMargin = 10;
    var scrollHeight = 252;
    var footerPosition = $('#footer').offset().top;

    if (scrollCostSummaryDivPosition > scrollHeight && scrollCostSummaryDivPosition <= (documentHeight - footerHeight - costSummaryHeight - headerHeight - footerMargin)) {
        stickySummary.removeAttr('style');
        stickySummary.addClass('fixed');

    } else if (scrollCostSummaryDivPosition > (documentHeight - footerHeight - costSummaryHeight - headerHeight - footerMargin)) {
        stickySummary.removeClass('fixed');
        stickySummary.css({
          "position" : "absolute",
          "top" : (documentHeight - footerHeight - costSummaryHeight - headerHeight - footerMargin - scrollHeight) + "px"
      });
    } else {
        stickySummary.removeClass('fixed');
        stickySummary.css({
            "position" : "absolute",
            "top" : "0"
        });
    }
}

$window.scroll(stickyCostSummary);
Gladine answered 17/11, 2016 at 12:51 Comment(0)
E
-1

All you have to do is position: fixed; and top: 0px; Its so simple. I use it in my web app.

Estaminet answered 9/12, 2023 at 1:38 Comment(1)
Please edit to make more obvious what additional insight you contrbute beyond existing and highlly upvoted answers like https://mcmap.net/q/80628/-how-can-i-make-a-div-stick-to-the-top-of-the-screen-once-it-39-s-been-scrolled-to . Ideally according to How to Answer. Currently your post gives an impression of "Thanks.", for only repeating what others have given and explained. Your post praises the solution instead of explaining it at all. That is causing the "I am not answering and only misuse this ansswer post for saying thanks." Please delete this, as an unregiistered user you need to first register or to flag your own post for a moderator to do the delete.Stolid

© 2022 - 2024 — McMap. All rights reserved.