<div class="page page1">Page 1</div>
  <div class="page page2">Page 2</div>
  <div class="page page3">Page 3</div>
  <div class="page page4">Page 4</div>
  <button class="scrollToTop">TOP</button>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  width: 100%;
}

html {
  scroll-behavior: smooth;
}

.page {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: xx-large;
}

.page:nth-child(odd){
  background-color: rgb(255, 231, 231);
}

.scrollToTop {
  position: fixed;
  bottom: 3rem;
  right: 3rem;
  padding: 0.5rem 0.25rem;
  border: 1px solid black;
  cursor: pointer;
  font-weight: bold;
  color: white;
  background-color: black;
  transform: translateY(50px);
  opacity: 0;
  transition: transform 0.5s, opacity 0.5s;
}

.showScrollToTop {
  opacity: 1;
  transform: translateY(0);
}
const page3 = document.querySelector(".page3")
const scrollToTop = document.querySelector(".scrollToTop")

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      scrollToTop.style.bottom = "3rem"
      scrollToTop.classList.add("showScrollToTop")
    } else {
      if (scrollToTop.classList.contains("showScrollToTop") && entry.boundingClientRect.y > 0) {
        scrollToTop.classList.remove("showScrollToTop")
        scrollToTop.addEventListener("transitionend", removeScrollFromView)
      }
    }
  })
})

function removeScrollFromView() {
  scrollToTop.removeEventListener("transitionend", removeScrollFromView)
  if (scrollToTop.classList.contains("showScrollToTop")) return
  scrollToTop.style.bottom = "-200px"
}

observer.observe(page3)

scrollToTop.addEventListener("click", () => {
  window.scrollTo({
    top: 0,
    behavior: "smooth",
  })
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.