0
\$\begingroup\$

I am currently working on a site product where I have to create a site-header that is always fixed on top of the viewport but when I scroll down it hides, and again when I scroll up, it becomes visible again. Actually, I made it happen somehow but I think the JQuery I used can be simpler and currently has some unnecessary variations in it. I used the JQuery from a reference available on internet.

Here is my code.

HTML

<header class="site-header">
    <div class="inner">
    </div>
</header>

CSS

.site-header {
position: fixed;
top: 0;
z-index: 1;
width: 100%;
height: 60px;
background: #fff;
transition: transform .25s;}

.hidden {transform:translateY(-100%)}

JQuery

jQuery( function( $ ) {
    var didScroll;
    var lastScrollTop = 0;
    var delta = 5;
    var navbarHeight = $('.site-header').outerHeight();

    $(window).scroll(function(event){
        didScroll = true;
    });

setInterval(function() {
    if (didScroll) {
    hasScrolled();
    didScroll = false;
    }
}, 250);

function hasScrolled() {
var st = $(this).scrollTop();

// Make scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
    return;

// If scrolled down and past the site-header, add class .hidden.
if (st > lastScrollTop && st > navbarHeight){
    // Scroll Down
    $('.site-header').addClass('hidden');
} else {
    // Scroll Up
    if(st + $(window).height() < $(document).height()) {
        $('.site-header').removeClass('hidden');
    }
}

lastScrollTop = st;
}
} );

Now, all these things together are functional and I have a header that is fixed; when I scroll down, it disappears and when I scroll back up, it becomes visible again - as I wanted. But, since I am not very familiar with JQuery, I am not sure whether this JQuery could be simpler. I think it would be great if I can achieve the same results with a smaller and simpler JQuery.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

First improvement I saw is about that always true condition:

if (st + $(window).height() < $(document).height())

The amount of pixel scrolled + the viewport height simply cannot be greater than the document height. ;)

Knowing this... You end up with a simple if/else condition to add or remove the hidden class. So instead of it, you can use toggleClass and use the condition result as the second argument.

function hasScrolled() {
  var st = $(this).scrollTop();

  // Make scroll more than delta
  if (Math.abs(lastScrollTop - st) <= delta) return;

  $(".site-header").toggleClass("hidden", st > lastScrollTop && st > navbarHeight);

  lastScrollTop = st;
}

Second is about the interval... I think it's useless to run the hasScrolled function every 250ms when this does the same visual effect:

$(window).scroll(hasScrolled);

Last: do not use var!. let or const are better. Read here

I left the delta in there, but for 5 pixels, I think it's useless too. Maybe there is a use-case for a bigger value...

Here is the improved code that I suggest:

jQuery(function ($) {
  let lastScrollTop = 0;
  const delta = 5;
  const navbarHeight = $(".site-header").outerHeight();
  const header = $(".site-header")

  $(window).scroll(hasScrolled);

  function hasScrolled() {
    const st = $(this).scrollTop();
    if (Math.abs(lastScrollTop - st) <= delta) return;
    header.toggleClass("hidden", st > lastScrollTop && st > navbarHeight);
    lastScrollTop = st;
  }
});

Without delta:

jQuery(function ($) {
  let lastScrollTop = 0;
  const navbarHeight = $(".site-header").outerHeight();
  const header = $(".site-header")

  $(window).scroll(hasScrolled);

  function hasScrolled() {
    const st = $(this).scrollTop();
    header.toggleClass("hidden", st > lastScrollTop && st > navbarHeight);
    lastScrollTop = st;
  }
});
\$\endgroup\$
3
  • \$\begingroup\$ Precisely, greatly explained. Thanks! I checked the code as well on the site, it is working absolutely fine. Since you mentioned, delta in the Jquery is also useless, can you please also provide a Jquery with delta removed? I would check it on the site and see if has any difference from the result I am expecting with the Jquery. \$\endgroup\$ Jan 8, 2023 at 2:54
  • \$\begingroup\$ Sure, it's done. You only had 2 lines to remove ;) \$\endgroup\$ Jan 8, 2023 at 3:00
  • 1
    \$\begingroup\$ Thanks! It works great. \$\endgroup\$ Jan 8, 2023 at 3:05
0
\$\begingroup\$

Jquery?

Jquery is dead, using it only adds bloat to the running code and noise to the source code.

We have a lot to thank JQuery for as it guided the development of modern DOM manipulation. So much so that using jQuery on modern browsers is pointless. Detrimental both to the page and the developer creating it.

Everyday you spend improving your jQuery skills is a day you lose learning modern DOM manipulation. Stay relevant?

Vanilla JS and DOM

Element.id

Give your elements (eg header) a unique id that you use to easily get references without the need to use DOM queries

<header class="site-header" id="navbarEl">
    <div class="inner">
    </div>
</header>

<script>
    console.log(navbarEl.offsetHeight); // show navbarEl height
</script>

window

When using vanilla JS window is the default this (AKA globalThis) and thus there is no need to reference it.

However you already use this pattern when referencing accessing window.document. Best you use the same pattern throughout the code. Using the less noisy default document, rather than window.document

Example

There are many more ways vanilla JS can improve your codes performance and decrease source complexity. However the existing answer has been accepted so I will just leave it with an rewrite example.

Note: that the example does not need to load and run jQuery and all DOM manipulations now use native methods

Note: that the code is started on the page load event (same as $.ready) which was missing from your code. This is important if the page headers' size is dependent on loaded content (eg images)

DOM referenced

addEventListener("load", () => {
    var lastY = scrollY;
    const MAX_SCROLL_DELTA = 5, NAV_HEIGHT = navbarEl.offsetHeight;
    addEventListener("scroll", () => {
       const delta = scrollY - lastY;
       if (Math.abs(delta) > MAX_SCROLL_DELTA) {
           navbarEl.classList.toggle("hiddeNavBar", delta > 0 && scrollY > NAV_HEIGHT);
           lastY = scrollY;
       }
    });
});
.site-header {
    position: fixed;
    top: 0;
    z-index: 1;
    width: 100%;
    height: 60px;
    background: #DDD;
    transition: transform 0.25s;
}

.hiddeNavBar {transform:translateY(-100%)}
.contentSpace { padding: 50px; }
<header class="site-header" id="navbarEl">
    <div class="inner"> Header
    </div>
</header>
<div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
<div class="contentSpace">Content</div>
</div>

\$\endgroup\$
4
  • \$\begingroup\$ I agree with you when it comes to develop a whole new application... jQuery can now be avoided. Now most devs will have to work on existing code to quickly add or modify a tiny feature. Knowing jQuery, as it was widely used for years and still is used in millions of sites, it is a card in hand. The choice to play it or not is opinion based. \$\endgroup\$ Jan 8, 2023 at 21:12
  • \$\begingroup\$ @LouysPatriceBessette Page speed is a very important factor in website’s ranking (SEO). It is not an opinion that using jQuery slows the page and puts the site at a disadvantage against not using jQuery. \$\endgroup\$
    – Blindman67
    Jan 9, 2023 at 17:38
  • \$\begingroup\$ Thanks Blindman67. Actually, I haven't much learned about DOM yet. I ain't kind of familiar to it. But, JQuery, it is being used by most websites till date. Also, I have my site integrated to WooCommerce that also has JQuery functionality. \$\endgroup\$ Jan 14, 2023 at 6:24
  • \$\begingroup\$ And, Blindman67, talking about SEO, it is a whole different thing. In my opinion, JQuery doesn't affect SEO rankings that much. Using HTML5 like <header>,<footer>,<nav>,<main>,<article>,<aside> and structuring your site well obviously gives an edge in SERP rankings. Also, talking about site speed, a site first loads basic structure, css. Then the browser loads the scripts. JS is a backend thing and a site first loads the frontend, so I don't think it much affects or slows site loading until it is overused everywhere. \$\endgroup\$ Jan 14, 2023 at 6:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.