How to use scrollTop as percentage rather than pixels

Viewed 187

I am animating divs to shrink when they start to get to the top of a page. Unfortunately, scrollTop is a pixel number which is not responsive-friendly since the pixel amounts will be different for every device.

My solution is to use percentage of the window but I'm still learning and I'm not sure how to do it. This is where I'm at so far-

https://codepen.io/muskaurochs/pen/NWNMOYG

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

function scrollFunction() {
  if (document.body.scrollTop > 200 || document.documentElement.scrollTop > 200) {
    document.getElementById("header").style.width = "80%";
  } else {
    document.getElementById("header").style.width = "100%";
  }
    if (document.body.scrollTop > 350 || document.documentElement.scrollTop > 350) {
    document.getElementById("header2").style.width = "80%";
  } else {
    document.getElementById("header2").style.width = "100%";
  }
    if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
    document.getElementById("header3").style.width = "80%";
  } else {
    document.getElementById("header3").style.width = "100%";
  }
}
2 Answers

You could do some sort of calculations to get the percentages but you don't need to do that. You should get the top of the div using offsetTop instead of adding in a fixed value, e.g.

if (document.body.scrollTop > document.getElementById("header").offsetTop || 
    document.documentElement.scrollTop > document.getElementById("header").offsetTop) {

The code you have for each header div is nearly the same so you could remove the repetition if you keep all the div elements in an array, and loop though that to get the offsetTop and set the style, like this:

function scrollFunction() {

  for (var i = 0; i < headerdivs.length; i++) {
    if (document.body.scrollTop > headerdivs[i].offsetTop || document.documentElement.scrollTop > headerdivs[i].offsetTop) {
      headerdivs[i].style.width = "80%";
    } else {
      headerdivs[i].style.width = "100%";
    }
  }
}

I used the code from your codepen here to show you how to make it work.

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

headerdivs = [
  document.getElementById("header"),
  document.getElementById("header2"),
  document.getElementById("header3"),
]

function scrollFunction() {

  for (var i = 0; i < headerdivs.length; i++) {
    if (document.body.scrollTop > headerdivs[i].offsetTop || document.documentElement.scrollTop > headerdivs[i].offsetTop) {
      headerdivs[i].style.width = "80%";
    } else {
      headerdivs[i].style.width = "100%";
    }
  }
}
body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
}

#header {
  background-color: #f1f1f1;
  color: black;
  text-align: center;
  font-weight: bold;
  width: 100%;
  transition: 1s;
  display: block;
}

#header2 {
  background-color: #f1f1f1;
  color: black;
  text-align: center;
  font-weight: bold;
  width: 100%;
  transition: 1s;
  display: block;
}

#header3 {
  background-color: #f1f1f1;
  color: black;
  text-align: center;
  font-weight: bold;
  width: 100%;
  transition: 1s;
  display: block;
}
<div id="header"><img src="https://image.freepik.com/free-photo/wide-asphalt-road-with-buildings-horizon_1127-2192.jpg" width=100%></div>
<div id="header2"><img src="https://image.freepik.com/free-photo/wide-asphalt-road-with-buildings-horizon_1127-2192.jpg" width=100%></div>
<div id="header3"><img src="https://image.freepik.com/free-photo/wide-asphalt-road-with-buildings-horizon_1127-2192.jpg" width=100%></div>

<div style="margin-top:200px;padding:15px 15px 2500px;font-size:30px">
  <p><b>This example demonstrates how to shrink a header when the user starts to scroll the page.</b></p>
  <p>Scroll down this frame to see the effect!</p>
  <p>Scroll to the top to remove the effect.</p>
  <p>Lorem ipsum dolor dummy text sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
    irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>

EDIT: You asked for how to change the distance from the top at which the div gets smaller. You can do this by adjusting the value of the top of the div. e.g. to start when the top of the div is half way up the screen:

// (position of the top of the div) - (half the screen height)
headerDiv.offsetTop - (window.innerHeight / 2);
function scrollFunction() {

  for (var i = 0; i < headerdivs.length; i++) {

    // adjust start point for changing the size, e.g.
    // (position of the top of the div) - (half the screen height)
    startChangingAt = (headerdivs[i].offsetTop) - (window.innerHeight / 2);
    if (startChangingAt < 0) startChangingAt = 0;

    if (document.body.scrollTop > startChangingAt || 
                  document.documentElement.scrollTop > startChangingAt ) 
      headerdivs[i].style.width = "80%";
    else 
      headerdivs[i].style.width = "100%";

  }
}

You could calculate the distance from the top of each section as well as their height. Then, you'll have to watch it that way.

let header = document.getElementById("header");
let boundingBox = header.getBoundingClientRect();
let distanceToTop = boundingBox.top;

if (document.body.scrollTop > distanceToTop || document.documentElement.scrollTop > distanceToTop) {
  document.getElementById("header").style.width = "80%";
} else {
  document.getElementById("header").style.width = "100%";
}

You can also play with the height of your section to add a percentage of visibility that will trigger the animation:


let header = document.getElementById("header");
let boundingBox = header.getBoundingClientRect();
let height = boundingBox.height;
let distanceToTop = boundingBox.top;

if (document.body.scrollTop > distanceToTop + height * 0.5|| document.documentElement.scrollTop > distanceToTop + height * 0.5) {
  document.getElementById("header").style.width = "80%";
} else {
  document.getElementById("header").style.width = "100%";
}

You Could also do it using the IntersectionObserver API, documentation here : https://developer.mozilla.org/fr/docs/Web/API/Intersection_Observer_API

Related