22/12/2024

Simple Javascript header resize on scroll

I have used this feature a lot on web site development, but never really investigated how it works : fixed header that shrinks when user scrolls down is a nice way of putting a bigger logo without comprising further reading.

requirements : tailwind, only ! we'll use pure javascript and a bit of css

first the html code , note that some elements are in brackets because I currently work with statamic antlers layout language. but most importantly here is the h-auto and w-24 initial sizing of the navigation bar logo

<div class="sticky top-0 z-50 bg-white shadow-md">
   <img src="{{ settings:logo }}" alt="{{ alt ?? 'Logo' }}" class="h-auto w-24"  id="wavelogo">
</div>

the css here is important to get a smooth transition

#wavelogo {
    transition: width 0.2s,
    height 0.5s,
    transform 0.2s;
}

and the javascript works with a limit value for the beginning of shrink effect, note that there a buffer value that will prevent flickering on most browsers

const elem = document.getElementById("wavelogo");
var  originalWidth=elem.style.width
var  originalHeight=elem.style.height
var originalRatio =elem.style.width / elem.style.height
window.onscroll = function() {
    console.log(window.scrollY)
    const buffer = 15;
    if(window.scrollY>=90+buffer){
        //user scrolled to the top of the page
        var w= 50
        elem.style.width = w + "px";
        elem.style.height = w/originalRatio+ "px";
    }
    else if (window.scrollY < (90 - buffer))
    {
        //user scrolled to the top of the page
        elem.style.width = originalWidth;
        elem.style.height = originalHeight;
    }
};

another technique to prevent flickering would be to use a timeout

let timeoutId;
window.onscroll = function() {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
        if(window.scrollY >= 90){
            var w = 50;
            elem.style.width = w + "px";
            elem.style.height = w/originalRatio + "px";
        } else {
            elem.style.width = originalWidth;
            elem.style.height = originalHeight;
        }
    }, 10); // 10ms delay
};
To top