JavaScript is causing a performance problem when attempting to hide the header while scrolling

In my attempt to create a navigation bar, I have specific requirements:

  • It should start with a large height
  • Disappear when scrolled down
  • Show a smaller version when scrolling back up
  • Expand to full height when fully scrolled to the top

I have managed to achieve this by using a function to hide and show the navigation bar, along with an interval to expand it again when reaching the top. However, I believe there might be a more efficient way to combine these actions. Any suggestions would be greatly appreciated!

HTML

<!DOCTYPE html>
  <html>
    <head>
      <title>Test</title>
    </head>
    <body>
      <header id="navbar" class="navbar">
        <a href="#home">Home</a>
        <a href="#news">News</a>
        <a href="#contact">Contact</a>
      </header>
    </body>
  </html>

JavaScript

var prevScrollpos = window.pageYOffset;
var shrinkHeader = 200;
function tellMeAStory() {
}

window.onscroll = function() {
  var currentScrollPos = window.pageYOffset;
  if (prevScrollpos > currentScrollPos) {
    document.getElementById("navbar").style.top = "0";
  } else {
    document.getElementById("navbar").style.top = "-200px";
    $('.navbar').addClass('shrink');
  }

  prevScrollpos = currentScrollPos;
}

setInterval(function(){
  var scroll = getCurrentScroll();
   if (scroll < 10){
    $('.navbar').removeClass('shrink');
  } else {}
},250)

function getCurrentScroll() {
    return window.pageYOffset || document.documentElement.scrollTop;
    };

CSS

body {
  margin: 0;
  background-color: #f1f1f1;
  font-family: Arial, Helvetica, sans-serif;
  height: 2000px;
}

header {
  background-color: #333;
  position: fixed;
  top: 0;
  width: 100%;
  display: block;
  transition: all 0.3s;
  height: 200px;
}

.grow{
  height: 200px;
}

.shrink{
  height: 50px;
}

#navbar a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 15px;
  text-decoration: none;
  font-size: 17px;
}

#navbar a:hover {
  background-color: #ddd;
  color: black;
}

JSFiddle

https://jsfiddle.net/Jimmey/wry54an7/4/

Answer №1

Here are a few enhancements I recommend implementing:

  • Consider removing jQuery for simply adding or removing a class.
  • Make sure to cache your selectors, especially within loops.
  • Implement scroll event throttling to avoid excessive firing.
  • Eliminate the unnecessary setInterval function in your code.

var prevScrollpos = getCurrentScroll();
var shrinkHeader = 200;
var ticking = false;

// Cache selectors to minimize on-scroll computations
var navbar = document.getElementById('navbar');

window.addEventListener('scroll', function() {
  var currentScrollPos = getCurrentScroll();

  if (!ticking) {
    window.requestAnimationFrame(function() {
      if (prevScrollpos > currentScrollPos) {
        navbar.style.top = '0';
      } else {
        navbar.style.top = '-200px';
        navbar.classList.add('shrink');
      }

      if (currentScrollPos < 10) {
        navbar.classList.remove('shrink');
      }

      prevScrollpos = currentScrollPos;
      ticking = false;
    });

    ticking = true;
  }
});

function getCurrentScroll() {
  return window.pageYOffset || document.documentElement.scrollTop;
};
body {
  margin: 0;
  background-color: #f1f1f1;
  font-family: Arial, Helvetica, sans-serif;
  height: 2000px;
}

header {
  background-color: #333;
  position: fixed;
  top: 0;
  width: 100%;
  display: block;
  transition: all 0.3s;
  height: 200px;
}

.grow {
  height: 200px;
}

.shrink {
  height: 50px;
}

#navbar a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 15px;
  text-decoration: none;
  font-size: 17px;
}

#navbar a:hover {
  background-color: #ddd;
  color: black;
}
<header id="navbar" class="navbar">
  <a href="#start">Start</a>
  <a href="#one">One</a>
  <a href="#two">Two</a>
</header>

Answer №2

Combining them is not a difficult task at all. One effective method is:

var prevScrollpos = window.pageYOffset;
var shrinkHeader = 200;

window.onscroll = function() {
var currentScrollPos = window.pageYOffset;
  if (currentScrollPos < 10){
    $('.navbar').removeClass('shrink');
  }
  else if (prevScrollpos > currentScrollPos) {
    document.getElementById("navbar").style.top = "0";
  } else {
    document.getElementById("navbar").style.top = "-200px";
    $('.navbar').addClass('shrink');
  }

  prevScrollpos = currentScrollPos;
}

function getCurrentScroll() {
    return window.pageYOffset || document.documentElement.scrollTop;
};

Another suggestion would be to track the last operation and, if it's the same, avoid making any unnecessary changes to the DOM (this can improve performance).

Using classes instead of inline styles is considered a best practice. You may want to utilize classes for displaying/hiding the bar. By having just 3 classes, you can eliminate the need for inline styles entirely:

Check out this Fiddle example demonstrating the use of classes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to connect CSS properties to an image using JavaScript?

I recently used JavaScript to insert an image into a webpage, but I'm unsure of how to make changes to it or position it properly. Is there a way to connect CSS styles to the image, or is there another method to modify it without relying on CSS? < ...

Reverting back to the specified CSS style

In my application, I have a common HTML component styled as follows: .box { min-width: 100px; padding: 20px 10px; } There are over 100 of these components and they each have a unique border style without a bottom border: .box:nth-child(1) { border ...

Incorporate a 'back' button in the tab content of vue-form-wizard

Currently, I'm working on implementing a vue form wizard from the repository: https://github.com/BinarCode/vue-form-wizard My challenge is to include a button in the second tab-content itself instead of having it placed in the footer. I attempted th ...

What is the proper way to transfer data to PHP using AJAX?

I'm facing an issue while trying to send FormData to a PHP file. When I press submit, nothing happens. However, when I send data separately, it works fine. <form method="post" class="code_form" enctype="multipart/form-data& ...

Troubleshooting Symfony2 and Assetic: Why are my CSS-linked images not loading?

I've encountered an issue with my CSS sprite sheet that my CSS file seems unable to locate the image. Despite following the provided solution here, I'm still facing the same problem. The directory structure of my bundle is as follows: src/ v ...

Guide on setting up create-next-app with version 12 instead of the latest version 13

For an upcoming Udemy course, I am required to develop a Next.js project. However, it specifically needs to be built using Next.js version 12 rather than the latest version 13. Does anyone know how I can achieve this? ...

Adjust the height of the floating div to completely occupy the space below it

I have multiple DIVs within my content container, some floating to the right and others to the left on screens larger than 400px. See working example here: https://jsfiddle.net/cmbpt1hd/ I need the height of area-three to automatically adjust so it fills ...

Seeking assistance in the development of a visual depiction of device orientation through JS

My goal is to visually represent the device orientation values alpha, beta, and gamma by creating a series of "bars" for each value. Currently, I have managed to display only the values in plain text using innerHTML. However, I envision these bars moving i ...

Guide on incorporating a PNG logo into the Tailwind CSS navbar using Next.js

I am attempting to replace the SVG logo in this code with a PNG logo, but every time I try to add an img element, nothing appears on the page. The new image/logo should be approximately the same size as the original SVG logo. https://i.sstatic.net/3Xuyj.j ...

fetch recently uploaded images from the server

I have successfully implemented image upload functionality to my server. Currently, I am storing the image within my user object like this: foto: { name: String, img: String, contentType: String }, When making a get request in AngularJS to retrieve all u ...

How numerous data attributes are available within Bootstrap? What functions do they perform and what possible values can be assigned to them?

Lately, I've been exploring the world of data attributes in Bootstrap such as data-toggle, data-trigger, and data-ride. However, my search for a comprehensive list of these attributes has come up short. I'm curious about the potential values tha ...

Generating a Simulation of a Computer Screen Embedded Within a Webpage

I have taken on the task of creating a website for a grant-funded documentary project. In this documentary, one of the characters is depicted as building a website about a specific topic. The idea is to display his computer, which is a hand-drawn graphic b ...

Invoke a server-side function with JavaScript or jQuery

Is it possible to call a server-side method using JavaScript or jQuery during a postback? I have a created an anchor button and I want it to function like a link button, triggering a postback and calling an event. I'm thinking that JavaScript might b ...

Generate arrays by extracting each individual value from a multidimensional array based on their corresponding index objects

Witness the example of my primary array: [ { 'data': [{'value': 'Yellow'}, {'value': 'Tiny'}, {'value': 'Excellent'}] }, { 'data': [{'value': 'Gre ...

Incorporate a sidebar navigation menu within the WordPress media uploader

Having an issue with a custom media upload feature I created using JavaScript code and the "wp.media" API. The problem is that the sidebar menu ('Insert from gallery', 'set featured image') is not displaying, unlike when adding an image ...

I attempt to demonstrate to my users, but unfortunately, it doesn't seem to be successful

My console.log is showing "undefined" for my users even though I can see them in my State. This issue started happening after implementing Redux - previously, it was working fine without Redux. Take a look at the code snippet from UserManagement.js: funct ...

What is the process for adjusting the input value dynamically in reactjs?

I am working on a dynamic time input row and I need to ensure that the values are updated correctly. This is the code snippet I am using: https://codesandbox.io/s/624vq8y7y3 When I run the code, the values in the TimeInput field do not change as expected ...

Incorporating ClojureScript seamlessly within a JavaScript framework

I am interested in using Clojurescript to develop a component within a JavaScript framework, but I am struggling with how to define the constructor and access global variables within the object. The framework generates views by fetching their state from a ...

Comparing the size of an array property in Mongoose with another property's size

Is it feasible to retrieve all documents containing an array property with a size greater or less than a specified number property? We are assuming that the numberProperty within the schema is of type Number and the array holds ObjectIds. For example: Co ...

Guide to utilizing reactstrap exclusively for a specific component within ReactJS

I am currently facing an issue in my project where I need to use Reactstrap but the project does not utilize Bootstrap. The problem arises when I try to install Bootstrap for Reactstrap, as it overrides my project styles which is not ideal. I want the comp ...