Stop content taking space under a sticky div

In this example when I click the "link" on the sticky header, how can I make the linked content item (#mypara) to appear below the sticky div and not directly underneath it so its hidden?

$(document).ready(function() {
    $(window).scroll(function() {
        var distanceFromTop = $(document).scrollTop();
        if (distanceFromTop >= $('#header').height())
        {
            $('#sticky').addClass('fixed');
        }
        else
        {
            $('#sticky').removeClass('fixed');
        }
    });
});
body { margin: 0px; background-color: #e3e3e3; }
#header { background-color: #cb5454; height: 140px; }
#sticky {
    background-color: #546bcb;
    height: 70px;
}
#sticky.fixed {
    display: block;
    position: fixed;
    top: 0;
    width: 100%;
}
p[id] {
  color:red;
  /*padding-top: 170px;*/
}
#footer { background-color: #cb5454; height: 140px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="header">header</div>
<div id="sticky">sticky <a href="#mypara">link</a></div>
<div id="section">
<p>section 1</p>
<p>section 2</p>
<p>section 3</p>
<p>section 4</p>
<p>section 5</p>
<p>section 6</p>
<p>section 7</p>
<p>section 8 x</p>
<p>section 9</p>
<p id="mypara">section 0 xxxx</p>
<p>section 1</p>
<p>section 2</p>
<p>section 3</p>
<p>section 4</p>
<p>section 5</p>
<p>section 6</p>
<p>section 7</p>
<p>section 8</p>
<p>section 9</p>
<p>section 0</p>
<p>section 1</p>
<p>section 2</p>
<p>section 3 z</p>
<p>section 4</p>
<p>section 5</p>
<p>section 6</p>
<p>section 7</p>
<p>section 7</p>
<p>section 8</p>
<p>section 8</p>
<p>section 9</p>
<p>section 0</p>
<p>section 1</p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section </p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
<p>section</p>
</div>
<div id="footer">foot</div>

This fiddle was inherited from other SO threads so I think this is the right way to do a sticky div that only becomes sticky after scrolling (I couldn't get position:sticky to do anything, but position:fixed seems to be whats recommended in a number of threads).

enter image description here

The above pic shows where I want it to land when the link is clicked

3 answers

  • answered 2018-11-08 08:34 Vikram Thakur

    In scroll function, you can first try to get window.pageYOffset which will give you current position of the scroll and then you can try using scrollTo(x, y) method of the window. Y value in the scrollTo will be the window.pageYOffset minus the height of your div. (window.pageYOffset - height of your div)

  • answered 2018-11-08 08:40 Abdullah Al Mamun

    `

    $(document).ready(function() {
            $(window).scroll(function() {
                var distanceFromTop = $(document).scrollTop();
                if (distanceFromTop >= $('#header').height())
                {
                    $('#sticky').addClass('fixed');
                }
                else
                {
                    $('#sticky').removeClass('fixed');
                }
            });
        });
    //add this. it will scroll to the div #mypara with 150px top offset
    $('a[href*=\\#]:not([href$=\\#])').click(function() {
        event.preventDefault();
        $('html, body').animate({
            scrollTop: $($.attr(this, 'href')).offset().top - 150
        }, 500);
    });
    body { margin: 0px; background-color: #e3e3e3; }
        #header { background-color: #cb5454; height: 140px; }
        #sticky {
            background-color: #546bcb;
            height: 70px;
        }
        #sticky.fixed {
            display: block;
            position: fixed;
            top: 0;
            width: 100%;
        }
        p[id] {
          color:red;
          /*padding-top: 170px;*/
        }
        #footer { background-color: #cb5454; height: 140px; }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <div id="header">header</div>
        <div id="sticky">sticky <a href="#mypara">link</a></div>
        <div id="section">
        <p>section 1</p>
        <p>section 2</p>
        <p>section 3</p>
        <p>section 4</p>
        <p>section 5</p>
        <p>section 6</p>
        <p>section 7</p>
        <p>section 8 x</p>
        <p>section 9</p>
        <p id="mypara">section 0 xxxx</p>
        <p>section 1</p>
        <p>section 2</p>
        <p>section 3</p>
        <p>section 4</p>
        <p>section 5</p>
        <p>section 6</p>
        <p>section 7</p>
        <p>section 8</p>
        <p>section 9</p>
        <p>section 0</p>
        <p>section 1</p>
        <p>section 2</p>
        <p>section 3 z</p>
        <p>section 4</p>
        <p>section 5</p>
        <p>section 6</p>
        <p>section 7</p>
        <p>section 7</p>
        <p>section 8</p>
        <p>section 8</p>
        <p>section 9</p>
        <p>section 0</p>
        <p>section 1</p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section </p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        <p>section</p>
        </div>
        <div id="footer">foot</div>

    `

  • answered 2018-11-08 10:00 user2728841

    As Jean-Marc Zimmer pointed out, using Sticky removed the need for javascript, but still had the problem of the element coming up underneath the sticky div.

    One solution was to add a pseudo element:

    p[id]::before {
      content: "";
      display: block;
      height: 60px; /* fixed header height*/
      margin: -60px 0 0; /* negative fixed header height */
    }
    

    Full fiddle here: http://jsfiddle.net/paull3876/8m3qwont/14/

    Note that position:sticky does not work in IE11.

    Note that adding padding or a border to p[id] (not in ::before) stops this effect working. No idea why!