sebastianross
sebastianross

Reputation: 43

Vertical scroll jumps when menubar fixes to top of screen

I've written a web page with a menu header that, when the page is scrolled down, fixes to the top when the menu header reaches the top of the page. But the code I found (absolute javascript beginner) and implemented creates a jump in the scrolling. From what I understand, this has to do with the css div height "vanishing" once I fix it to the top of the page. HTML:

  <div class="home-header">
    <div class="caption">
    </div>
  </div>

  <div class="header" id="header">
    <ul class="nav">
      <li><a href="">PAGE 1</a></li>
      <li><a href="">PAGE 2</a></li>
      <li><a href="">PAGE 3</a></li>
      <li><a href="">PAGE 4</a></li>
    </ul>
  </div>

CSS:

body {
  margin: 0;
}
.home-header {
  display: flex;
  justify-content: center;
  align-items: center;
  background: url('https://images.unsplash.com/photo-1495443396064-16fd983acb6a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80') center no-repeat;
  background-size: cover;
  width: 100vw;
  height: 35vw;
}
.caption {
  color: #f2f2ee;
}
/* NAVIGATION */
.header {
  padding-top: 5px;
  padding-bottom: 5px;
  font-family: proxima-nova, sans-serif;
  font-weight: 400;
  font-style: normal;
  background: #888;
}
.sticky {
  position: fixed;
  top: 0;
  background-color: #18361f;
  width: 100%;
  background: #888;
}
.nav {
  width: 100%;
  padding: 0;
  display: table;
  text-align: center;
  font-size: 1rem;
  list-style: none;
}
.nav li {
  display: inline-block;
  float: none;
  margin-right: 15px;
  margin-left: 15px;
}

Javascript:

window.onscroll = function() {myFunction()};

    var header = document.getElementById("header");
    var sticky = header.offsetTop;

    function myFunction() {
      if (window.pageYOffset > sticky) {
        header.classList.add("sticky");
      } else {
        header.classList.remove("sticky");
      }
    }

JSFiddle of the code with the problem. I currently run the javascript code directly in my html file with <script> </script> commands. I've tried the stackexchange answer here, but it doesn't work, and another solution I found (I can't find the stackexchange page anymore), causes the menubar to jump to the top of the browser screen before it should actually arrive there. Is there another solution I can use to fix this scroll jumping issue? (I did add the jquery api into the header of my html when I ran the above solution code.)

Upvotes: 1

Views: 1078

Answers (3)

Brent Stees
Brent Stees

Reputation: 342

You might want to use position: sticky;...

.sticky {
  position: -webkit-sticky; /* Safari */
  position: sticky;
  top: 0;
}

... it's rather new so watch your browser version requirements.

Edit: a pen for this... https://codepen.io/bstees/pen/yLyMZYE

Upvotes: 1

Digglit
Digglit

Reputation: 686

You can do this with just CSS no JavaScript required. I've modified your fiddle to do just that.

I added these to your header CSS class.

position: sticky;
top: 0;

https://jsfiddle.net/jd3etnyc/

body {
  margin: 0;
}

.home-header {
  display: flex;
  justify-content: center;
  align-items: center;
  background: url('https://images.unsplash.com/photo-1495443396064-16fd983acb6a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80') center no-repeat;
  background-size: cover;
  width: 100vw;
  height: 35vw;
}

.caption {
  color: #f2f2ee;
}


/* NAVIGATION */

.header {
  padding-top: 5px;
  padding-bottom: 5px;
  font-family: proxima-nova, sans-serif;
  font-weight: 400;
  font-style: normal;
  background: #888;
  position: sticky;
  top: 0;
}

.sticky {
  position: fixed;
  top: 0;
  background-color: #18361f;
  width: 100%;
  background: #888;
}

.nav {
  width: 100%;
  padding: 0;
  display: table;
  text-align: center;
  font-size: 1rem;
  list-style: none;
}

.nav li {
  display: inline-block;
  float: none;
  margin-right: 15px;
  margin-left: 15px;
}
<div class="home-header">
  <div class="caption">
  </div>
</div>

<div class="header" id="header">
  <ul class="nav">
    <li><a href="">PAGE 1</a></li>
    <li><a href="">PAGE 2</a></li>
    <li><a href="">PAGE 3</a></li>
    <li><a href="">PAGE 4</a></li>
  </ul>
</div>
blabla1<br>blabla2<br>blabla3<br>blabla4<br>blabla5<br>blabla6<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla
<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla<br>blabla

Upvotes: 1

hungerstar
hungerstar

Reputation: 21715

Sticky headers overlay other elements on the page. Prior to scrolling, you will need to add a "buffer" to the content so it is not initially overlay-ed. This buffer is achieved with margin/padding and usually starts with an amount that matches the height of the sticky header.

Below I've updated your code to add this "buffer" via a class.

Note: This is for sticky headers using fixed positioning.

window.onscroll = function() {
  myFunction()
};

var header = document.getElementById("header");
var main   = document.querySelector( 'main' );
var sticky = header.offsetTop;

function myFunction() {
  if (window.pageYOffset > sticky) {
    header.classList.add("sticky");
    main.classList.add( 'sticky-buffer' );
  } else {
    header.classList.remove("sticky");
    main.classList.remove( 'sticky-buffer' );
  }
}
body {
  margin: 0;
}

.home-header {
  display: flex;
  justify-content: center;
  align-items: center;
  background: url('https://images.unsplash.com/photo-1495443396064-16fd983acb6a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80') center no-repeat;
  background-size: cover;
  width: 100vw;
  height: 35vw;
}

.caption {
  color: #f2f2ee;
}


/* NAVIGATION */

.header {
  padding-top: 5px;
  padding-bottom: 5px;
  font-family: proxima-nova, sans-serif;
  font-weight: 400;
  font-style: normal;
  background: #888;
}

.sticky {
  position: fixed;
  top: 0;
  background-color: #18361f;
  width: 100%;
  background: #888;
}

.sticky-buffer {
  padding-top: 60px; /* <-- .header height */
}

.nav {
  width: 100%;
  padding: 0;
  display: table;
  text-align: center;
  font-size: 1rem;
  list-style: none;
}

.nav li {
  display: inline-block;
  float: none;
  margin-right: 15px;
  margin-left: 15px;
}
<div class="home-header">
  <div class="caption">
  </div>
</div>

<div class="header" id="header">
  <ul class="nav">
    <li><a href="">PAGE 1</a></li>
    <li><a href="">PAGE 2</a></li>
    <li><a href="">PAGE 3</a></li>
    <li><a href="">PAGE 4</a></li>
  </ul>
</div>

<main>
  blabla1
  <br> blabla2
  <br> blabla3
  <br> blabla4
  <br> blabla5
  <br> blabla6
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
  <br> blabla
</main>

Upvotes: 0

Related Questions