Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scroll to section by section

I have HTML markup:

HTML:

<body>
    <header></header>

    <nav>
        <ul>
            <li><a href="#one">one</a></li>
            <li><a href="#two">two</a></li>
        </ul>
    </nav>

    <section id="one"></section>
    <section id="two"></section>

    <footer></footer>
</body>

where section is fullscreen (width: 100%; height:100%;) and menu have absolute position.

Question:

  1. How can I use mouse scroll (or keys ) to scroll and snap to each section?
  2. When scroll to last section then scroll-down to #one again and repeat it.
  3. When I click on link, it scroll to section.

Thank you for your suggestions, ideas, code.

like image 637
Ing. Michal Hudak Avatar asked Oct 02 '13 10:10

Ing. Michal Hudak


People also ask

How do I scroll to a section in JavaScript?

You need scroll-snap-type: y mandatory; on the container and scroll-snap-align: start; on the sections.

What is scroll-snap-align?

The scroll-snap-align property specifies the box's snap position as an alignment of its snap area (as the alignment subject) within its snap container's snapport (as the alignment container). The two values specify the snapping alignment in the block axis and inline axis, respectively.

How do you add a section to a scroll in HTML?

By using the <Style> tag, we will add the scroll options in HTML Page itself.


2 Answers

Interesting

I stole this code, changed the layout and tried to add the functions you mentioned (1. scroll-snap + 2. scroll when link is clicked). Unfortunately, I can't have this second function to work.

  1. Adding scroll-snap is not a problem

You need scroll-snap-type: y mandatory; on the container and scroll-snap-align: start; on the sections.

var doc = window.document,
  context = doc.querySelector('.js-loop'),
  clones = context.querySelectorAll('.is-clone'),
  disableScroll = false,
  scrollHeight = 0,
  scrollPos = 0,
  clonesHeight = 0,
  i = 0;

function getScrollPos () {
  return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}

function setScrollPos (pos) {
  context.scrollTop = pos;
}

function getClonesHeight () {
  clonesHeight = 0;

  for (i = 0; i < clones.length; i += 1) {
    clonesHeight = clonesHeight + clones[i].offsetHeight;
  }

  return clonesHeight;
}

function reCalc () {
  scrollPos = getScrollPos();
  scrollHeight = context.scrollHeight;
  clonesHeight = getClonesHeight();

  if (scrollPos <= 0) {
    setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
  }
}

function scrollUpdate () {
  if (!disableScroll) {
    scrollPos = getScrollPos();

    if (clonesHeight + scrollPos >= scrollHeight) {
      // Scroll to the top when you’ve reached the bottom
      setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
      disableScroll = true;
    } else if (scrollPos <= 0) {
      // Scroll to the bottom when you reach the top
      setScrollPos(scrollHeight - clonesHeight);
      disableScroll = true;
    }
  }

  if (disableScroll) {
    // Disable scroll-jumping for a short time to avoid flickering
    window.setTimeout(function () {
      disableScroll = false;
    }, 40);
  }
}

function init () {
  reCalc();
  
  context.addEventListener('scroll', function () {
    window.requestAnimationFrame(scrollUpdate);
  }, false);

  window.addEventListener('resize', function () {
    window.requestAnimationFrame(reCalc);
  }, false);
}

if (document.readyState !== 'loading') {
  init()
} else {
  doc.addEventListener('DOMContentLoaded', init, false)
}
html,
body {
  height: 100%;
  overflow: hidden;
}

.Loop {
  position: relative;
  height: 100%;
  overflow: scroll;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: y mandatory;
}

section {
  position: relative;
  text-align: center;
  height: 100%;
  scroll-snap-align: start;
}

::scrollbar {
  display: none;
}


body {
  font-family: "Avenir Next", Helvetica, sans-serif;
  font-weight: normal;
  font-size: 100%;
  position: relative;
}

nav {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 10;
}

nav ul {
  display: flex;
  justify-content: space-around;
  margin: 0;
  padding: 1rem 0;
}

nav ul li{
  display: flex;
  justify-content: space-around;
}

.nav-link{
  text-decoration: none;
  color: grey
}

.one {
  background: black;
}
.two {
  background: darkblue;
}
.three {
  background: lightgreen;
}
.four {
  background: lightcoral;
}
.five {
  background: lightskyblue;
}
.six {
  background: orange;
}

h1 {
  margin: 0;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 100%;
  font-size: 80px;
  letter-spacing: 5px;
  color: #fff;
  text-transform: uppercase;
}
<nav>
  <ul>
    <li><a class="nav-link" href="#one">one</a></li>
    <li><a class="nav-link" href="#two">two</a></li>
    <li><a class="nav-link" href="#three">three</a></li>
    <li><a class="nav-link" href="#four">four</a></li>
    <li><a class="nav-link" href="#five">five</a></li>
    <li><a class="nav-link" href="#six">six</a></li>
  </ul>
</nav>
<main class="Loop js-loop">
  <section class="one" id="one">
    <h1>One</h1>
  </section>
  <section class="two" id="two">
    <h1>Two</h1>
  </section>
  <section class="three" id="three">
    <h1>Three</h1>
  </section>
  <section class="four" id="four">
    <h1>Four</h1>
  </section>
  <section class="five" id="five">
    <h1>Five</h1>
  </section>
  <section class="six" id="six">
    <h1>Six</h1>
  </section>

  <!--
  These blocks are the same as the first blocks to get that looping illusion going.
  You need to add clones to fill out a full viewport height.
  -->
  <section class="one is-clone">
    <h1>One</h1>
  </section>
  <section class="two is-clone">
    <h1>Two</h1>
  </section>

</main>
  1. Adding the scrolling when you click on the link is a problem

With a normal container you only need to add the scroll-behaviour: smooth; to it. But here if you do that, you will lose the loop illusion because you will see it scroll back to the first instead of seemingly continue. (and it will also start an infinite back and forth scrolling that I couldn't fix yet)

var doc = window.document,
  context = doc.querySelector('.js-loop'),
  clones = context.querySelectorAll('.is-clone'),
  disableScroll = false,
  scrollHeight = 0,
  scrollPos = 0,
  clonesHeight = 0,
  i = 0;

function getScrollPos () {
  return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}

function setScrollPos (pos) {
  context.scrollTop = pos;
}

function getClonesHeight () {
  clonesHeight = 0;

  for (i = 0; i < clones.length; i += 1) {
    clonesHeight = clonesHeight + clones[i].offsetHeight;
  }

  return clonesHeight;
}

function reCalc () {
  scrollPos = getScrollPos();
  scrollHeight = context.scrollHeight;
  clonesHeight = getClonesHeight();

  if (scrollPos <= 0) {
    setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
  }
}

function scrollUpdate () {
  if (!disableScroll) {
    scrollPos = getScrollPos();

    if (clonesHeight + scrollPos >= scrollHeight) {
      // Scroll to the top when you’ve reached the bottom
      setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
      disableScroll = true;
    } else if (scrollPos <= 0) {
      // Scroll to the bottom when you reach the top
      setScrollPos(scrollHeight - clonesHeight);
      disableScroll = true;
    }
  }

  if (disableScroll) {
    // Disable scroll-jumping for a short time to avoid flickering
    window.setTimeout(function () {
      disableScroll = false;
    }, 40);
  }
}

function init () {
  reCalc();
  
  context.addEventListener('scroll', function () {
    window.requestAnimationFrame(scrollUpdate);
  }, false);

  window.addEventListener('resize', function () {
    window.requestAnimationFrame(reCalc);
  }, false);
}

if (document.readyState !== 'loading') {
  init()
} else {
  doc.addEventListener('DOMContentLoaded', init, false)
}
html,
body {
  height: 100%;
  overflow: hidden;
}

.Loop {
  position: relative;
  height: 100%;
  overflow: scroll;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
}

section {
  position: relative;
  text-align: center;
  height: 100%;
  scroll-snap-align: start;
}

::scrollbar {
  display: none;
}


body {
  font-family: "Avenir Next", Helvetica, sans-serif;
  font-weight: normal;
  font-size: 100%;
  position: relative;
}

nav {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 10;
}

nav ul {
  display: flex;
  justify-content: space-around;
  margin: 0;
  padding: 1rem 0;
}

nav ul li{
  display: flex;
  justify-content: space-around;
}

.nav-link{
  text-decoration: none;
  color: grey
}

.one {
  background: black;
}
.two {
  background: darkblue;
}
.three {
  background: lightgreen;
}
.four {
  background: lightcoral;
}
.five {
  background: lightskyblue;
}
.six {
  background: orange;
}

h1 {
  margin: 0;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 100%;
  font-size: 80px;
  letter-spacing: 5px;
  color: #fff;
  text-transform: uppercase;
}
<nav>
  <ul>
    <li><a class="nav-link" href="#one">one</a></li>
    <li><a class="nav-link" href="#two">two</a></li>
    <li><a class="nav-link" href="#three">three</a></li>
    <li><a class="nav-link" href="#four">four</a></li>
    <li><a class="nav-link" href="#five">five</a></li>
    <li><a class="nav-link" href="#six">six</a></li>
  </ul>
</nav>
<main class="Loop js-loop">
  <section class="one" id="one">
    <h1>One</h1>
  </section>
  <section class="two" id="two">
    <h1>Two</h1>
  </section>
  <section class="three" id="three">
    <h1>Three</h1>
  </section>
  <section class="four" id="four">
    <h1>Four</h1>
  </section>
  <section class="five" id="five">
    <h1>Five</h1>
  </section>
  <section class="six" id="six">
    <h1>Six</h1>
  </section>

  <!--
  This block is the same as the first block to get that looping illusion going.
  You need to add clones to fill out a full viewport height.
  -->
  <section class="one is-clone">
    <h1>One</h1>
  </section>
  <section class="two is-clone">
    <h1>Two</h1>
  </section>

</main>

I know this code is not 100% functional yet, but I think it can lead us to a better answer.

like image 189
tamarin Avatar answered Oct 06 '22 01:10

tamarin


You can use ID in this case.

Set the ID for your section and add anchor tag and set href attribute to your section id.

<a href="#YourSectionID">Go Up</a> <!-- don't forget # before write your ID. -->

Don't forget set scroll-behavior to smooth for smooth scrolling.

like image 32
Ehsan Akbarzadeh Avatar answered Oct 06 '22 01:10

Ehsan Akbarzadeh