So I have this navbar with a logo on it. I would like the logo to be big when the user is in the header section of the page, but then shrink when the user scrolls down. Any
Sorry for spoiling the party, but setting a height or width in javascript for sophisticated design will leave you with hundreds of assignments for the style, even though w3schools suggests something like this. Sure it works for simple things.
Think about this solution when you have a mobile browser as well, keyword "responsive design"- what will you do? Javascript is not the right place to set some actual sizes or distances. I would rather just do a single thing: just add a class to the body
element and remove it when scrolled back. With other solutions I would make several adjustments per scroll event, which is a lot.
So adding a class is much more efficient (works in modern browsers, for IE 9 or lower you have to do something different):
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.body.classList.add("minilogo");
} else {
document.body.classList.remove("minilogo");
}
}
Then in your css you can set the proper width and height and top and left and whatsoever, like:
body.minilogo .navbar-brand img {
width: 30px;
}
Further Considerations:
Using this simple if scrolled then ... else
solution can be a problem in some corner-cases is that there can happen some flickering, if by resizing the logo the space gets enough so that the scrolling gets reduced so that the else
case is hit again and a cycle is reached if the user tries to scroll (it is hard to describe, but you see it is a corner case). So it can be useful to add an if
to the else case like this:
if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.body.classList.add("minilogo");
}
} else if (document.body.scrollTop < 10 && document.documentElement.scrollTop < 10) {
document.body.classList.remove("minilogo");
}
This will prevent these kind of cycles for cases in which the
normal logo height in pixels - small logo height in pixels < 40 pixels.
Be aware that some browsers like iPad Safari makes the URL area etc invisible when you scroll down which makes more space available to your site reducing the scrolling value as well. This can also lead to resizing cycles when the user keeps scrolling. The same applies for -I think all- Safari iOS which have this rubber band scrolling mechanism that allows scrolling above unreasonable values and then will jump back to original place like a loaded spring. So the max available scroll value has to be taken into account as well.
Final Solution So at the end I come up with the following solution, which satisfied me and had no flickering (requires JQuery):
function scrollFunction() {
let scrollMax=$(document).height()-$(window).height();
if (Math.min(document.body.scrollTop, scrollMax) > 70 || Math.min(document.documentElement.scrollTop, scrollMax) > 70 && document.documentElement.scrollTop<=scrollMax) {
document.body.classList.add("minilogo");
} else if (document.body.scrollTop < 5 && document.documentElement.scrollTop < 5) {
document.body.classList.remove("minilogo");
}
}
Took me quite some time, so enjoy!
You can do this with regular JS. You can trigger the change with a pixel accuracy, my example will trigger when you are 5 pixels from the top.
Place this script in your <head>
.
<script>
window.onscroll = function() {
growShrinkLogo()
};
function growShrinkLogo() {
var Logo = document.getElementById("Logo")
if (document.body.scrollTop > 5 || document.documentElement.scrollTop > 5) {
Logo.style.width = '30px';
} else {
Logo.style.width = '60px';
}
}
</script>
and replace <img src="Images/logo.png" width="60px">
with <img src="Images/logo.png" style="width:60px" id='Logo'>
You can achieve this using JQuery-
$(document).scroll(function() {
$('#navbar').css({width: $(this).scrollTop() > 100? "50%":"100%"});
});
explanation- When scrolling- get the navbar element, change it's CSS as follows: if scrollTop() < 100 (we're not at the top of the page) - change the width to 50%. Otherwise change it to 100% (regular)
Bare in mind that the suggested solutions so far will apply the css on every single scroll event (literally hundreds or even thousands of times), decreasing scrolling smoothness/performance.
I've made a little addition to the solution from Robin Wright which you can find a fiddle of here to test it. This ensures that the css is only applied when you cross the border of the header (in this case 150px).
The code is the following:
window.onscroll = function() {
growShrinkLogo()
};
var Logo = document.getElementById("Logo");
var endOfDocumentTop = 150;
var size = 0;
function growShrinkLogo() {
var scroll = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
if (size == 0 && scroll > endOfDocumentTop) {
Logo.style.width = '30px';
size = 1;
} else if(size == 1 && scroll <= endOfDocumentTop){
Logo.style.width = '60px';
size = 0;
}
}
PS. in the fiddle i've also added a transition for the logo.