1

My page has a fullscreen teaser at the top. When the user starts scrolling I want the whole page to scroll down to the following segment automatically and smoothly.

Unfortunately the following code does not work. As posted it does not scroll at all and when I don't set the scrolling variable to true to avoid multiple scrollIntoView executions it's super slow.

What's a good way to fix this using vanilla JS?

Example, tested in Chrome:

let scrolling = false;

window.onscroll = () => {
  const offset = window.pageYOffset;
  if (offset > 0 && offset < window.innerWidth && !scrolling) {
    scrolling = true;
    document.querySelector('.somecontent').scrollIntoView({behavior:'smooth'});
  }
  
  if (offset >= window.innerWidth) {
    scrolling = false;
  }
}
.someteaser {
  background: blue;
  height: 100vh;
  width: 100vw;
}

.somecontent {
  background: red;
  height: 200vh;
  width: 100vw;
}
<div class="someteaser"></div>
<div class="somecontent"></div>

// Update

So the problem is the behavior:'smooth' option. Without it the scrolling works, but of course isn't smooth anymore. This seems to be a bug on scorllIntoView which I don't really understand. My temporary solution uses this script, which works alright: https://github.com/cferdinandi/smooth-scroll

JockelzF
  • 423
  • 2
  • 7
  • 15
  • Not sure exactly what you're trying to achieve, but if I get the general idea I'd be a bit confused and annoyed if the page started scrolling out of my control – freefaller May 10 '19 at 14:34
  • this is very common in modern webdesign. here is a popular framework for this https://alvarotrigo.com/fullPage/ which unfortunately has other problems, so this is no solution for me. – JockelzF May 10 '19 at 14:38
  • don't you want it to be run in `window.onload` instead? as for the smooth scroll function, there are loads of libraries that do it. you can look at a nice example in [this SO answer](https://stackoverflow.com/a/51689657/3148807) – Sagiv b.g May 10 '19 at 14:44
  • looks like you need to animate your offset giving it an easing effect. you can split it into 2 tasks - 1 - find the way to set your offset so your pages will look presentative, 2 - animate the offset. – user1514042 May 10 '19 at 14:45
  • whitch problems for you in with alvarotrigo.com/fullPage ? _(one is enough)_ – Mister Jojo May 10 '19 at 16:17
  • Was buggy for me in IE11, which I have to support here. – JockelzF May 10 '19 at 16:52
  • Did you see my answer ?, did you test it ? do you have a feedback ? – Mister Jojo May 12 '19 at 21:15
  • sorry, i dont work on weekends ;) It's a very nice solution you coded there – JockelzF May 13 '19 at 08:31

1 Answers1

1

The problem interested me, so I did that, trying to make it wider (it's self-scrolling up and down). I hope it suits your question ..

(snippet is better working here on full page)

const
  AllSections   = document.querySelectorAll('body > section'), // all target Section reference
  SectionsCount = AllSections.length,
  opt           = {behavior: "smooth", block: "start"};

var
  NoSmooth       = true, // autoScroll is off
  Last_W_PosY    = 0,    // used to determine scrolling event direction
  Smooth_Id      = 0,    // setTimeout for launching autoScroll
  Smooth_End     = 0,    // setinterval to detect end of autoScroll
  Scroll2Section = -1;   // target section for autoScroll

window.onscroll = () => {
  clearTimeout(Smooth_Id);
  let
    W_PosY    = window.pageYOffset,
    W_height  = window.innerHeight,
    direction = (Last_W_PosY < W_PosY) ? 'down' : 'up';

  if (NoSmooth){
    Scroll2Section = -1;
    let parts_Section = true;

    for(let i = 0; i< SectionsCount; i++){
      let SectionRect = AllSections[i].getBoundingClientRect();
      if ( SectionRect.y <= 0 && (SectionRect.height + SectionRect.y) >= W_height )
      {
        parts_Section = false;
        break;
      }
    }
    if (parts_Section){
      if (direction==='down') {
        for (let i = 0; i< SectionsCount; i++){
          if (AllSections[i].getBoundingClientRect().y > 0 ) {
            Scroll2Section = i;
            break;
          }
        }
      }
      if (direction==='up') {
        for (let i = SectionsCount; i-->0;){
          if (AllSections[i].getBoundingClientRect().y < 1) { // somme top position are not precise
            Scroll2Section = i;
            break;
          }
        }
      }
    }

    if (parts_Section) {
      Smooth_Id = setTimeout(Smooth_Action, 300) // reaction delay for auto scroll
    }
  }
  Last_W_PosY = W_PosY;
}

function Smooth_Action(){
  NoSmooth = false;
  AllSections[Scroll2Section].scrollIntoView( opt );
  clearInterval(Smooth_End);
  Smooth_End = setInterval(Wait_Smooth_Finish, 100 )
}

function Wait_Smooth_Finish(){
  let W_PosY = window.pageYOffset;
  if (Last_W_PosY==W_PosY) {
    NoSmooth = true;
    clearInterval(Smooth_End);
  }
  Last_W_PosY = W_PosY;
}
body           { margin: 0; }
body > section { display: block; width: 100%; margin: 0  }
.content_0     { height: 100vh; background: #001f3f; }
.content_1     { height: 120vh; background: #FF851B; }
.content_2     { height: 140vh; background: #39CCCC; }
.content_3     { height: 160vh; background: #F012BE; }
p { display:inline-block; margin:20px; padding:3px; background-color:#f0f8ff }
<section class="content_0"> <p>1 / 4</p> </section>
<section class="content_1"> <p>2 / 4</p> </section>
<section class="content_2"> <p>3 / 4</p> </section>
<section class="content_3"> <p>4 / 4</p> </section>
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40