Make element fixed on scroll

前端 未结 10 2432
臣服心动
臣服心动 2020-12-23 02:09

I\'m attempting to make the navigation bar stick to the top, when the user scrolls down to the nav bar and then unstick when the user scrolls back up past the navbar. I unde

10条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-23 02:33

    There are some problems implementing this which the original accepted answer does not answer:

    1. The onscroll event of the window is firing very often. This implies that you either have to use a very performant listener, or you have to delay the listener somehow. jQuery Creator John Resig states here how a delayed mechanism can be implemented, and the reasons why you should do it. In my opinion, given todays browsers and environments, a performant listener will do as well. Here is an implementation of the pattern suggested by John Resig
    2. The way position:fixed works in css, if you scroll down the page and move an element from position:static to position: fixed, the page will "jump" a little because the document "looses" the height of the element. You can get rid of that by adding the height to the scrollTop and replace the lost height in the document body with another object. You can also use that object to determine if the sticky item has already been moved to position: fixed and reduce the calls to the code reverting position: fixed to the original state: Look at the fiddle here
    3. Now, the only expensive thing in terms of performance the handler is really doing is calling scrollTop on every call. Since the interval bound handler has also its drawbacks, I'll go as far as to argue here that you can reattach the event listener to the original scroll Event to make it feel snappier without many worries. You'll have to profile it though, on every browser you target / support. See it working here

    Here's the code:

    JS

    /* Initialize sticky outside the event listener as a cached selector.
     * Also, initialize any needed variables outside the listener for 
     * performance reasons - no variable instantiation is happening inside the listener.
     */
    var sticky = $('#sticky'),
        stickyClone,
        stickyTop = sticky.offset().top,
        scrollTop,
        scrolled = false,
        $window = $(window);
    
    /* Bind the scroll Event */
    $window.on('scroll', function (e) {
        scrollTop = $window.scrollTop();
    
        if (scrollTop >= stickyTop && !stickyClone) {
            /* Attach a clone to replace the "missing" body height */
            stickyClone = sticky.clone().prop('id', sticky.prop('id') + '-clone')
            stickyClone = stickyClone.insertBefore(sticky);
            sticky.addClass('fixed');
        } else if (scrollTop < stickyTop && stickyClone) {
            /* Since sticky is in the viewport again, we can remove the clone and the class */
            stickyClone.remove();
            stickyClone = null;
            sticky.removeClass('fixed');
        }
    });
    

    CSS

    body {
        margin: 0
    }
    .sticky {
        padding: 1em;
        background: black;
        color: white;
        width: 100%
    }
    .sticky.fixed {
        position: fixed;
        top: 0;
        left: 0;
    }
    .content {
        padding: 1em
    }
    

    HTML

    Some Content above sticky

    ...some long text...
    This is sticky

    Some Random Page Content

    ...some really long text...

提交回复
热议问题