<div class="container">
  <div class="controller">
    <a href="#offset0">to 0</a>
    <a href="#offset3000">to 3000</a>
    <a class="js-scroll" href="#offset3000">to 3000 with scroll</a>
    <a href="#sub">to sub</a>
  </div>
  <p class="cls-score js-cls">0</p>
  <section id="offset0" class="wrapper">
    <div class="contents">0</div>
  </section>
  <section class="wrapper">
    <div class="contents">200</div>
  </section>
  <section class="wrapper">
    <div class="contents">400</div>
  </section>
  <section class="wrapper">
    <div class="contents">600</div>
  </section>
  <section class="wrapper">
    <div class="contents">800</div>
  </section>
  <section class="wrapper">
    <div class="contents">1000</div>
  </section>
  <section class="wrapper">
    <div class="contents">1200</div>
  </section>
  <section class="wrapper">
    <div class="contents">1400</div>
  </section>
  <section class="wrapper">
    <div class="contents">1600</div>
  </section>
  <section class="wrapper">
    <div class="contents">1800</div>
  </section>
  <section class="wrapper">
    <div class="contents">2000</div>
  </section>
  <section class="wrapper">
    <div class="contents">2200</div>
  </section>
  <section class="wrapper">
    <div class="contents">2400</div>
  </section>
  <section class="wrapper">
    <div class="contents">2600</div>
  </section>
  <section class="wrapper">
    <div class="contents">2800</div>
  </section>
  <section id="offset3000" class="wrapper">
    <div class="contents">3000</div>
  </section>
  <section class="wrapper">
    <div class="contents">3200</div>
  </section>
  <section class="wrapper">
    <div class="contents">3400</div>
  </section>
  <section class="wrapper">
    <div class="contents">3600</div>
  </section>
  <section class="wrapper">
    <div class="contents">3800</div>
  </section>
  <section class="wrapper">
    <div class="contents">4000</div>
  </section>
  <section class="wrapper">
    <div class="contents">4200</div>
  </section>
  <section class="wrapper">
    <div class="contents">4400</div>
  </section>
  <section class="wrapper">
    <div class="contents">4600</div>
  </section>
  <section class="wrapper">
    <div class="contents">4800</div>
  </section>
  <section class="wrapper">
    <div class="contents">5000
      <div id="sub" class="contents__sub">sub</div>
    </div>
  </section>
  <section class="wrapper">
    <div class="contents">5200</div>
  </section>
  <section class="wrapper">
    <div class="contents">5400</div>
  </section>
  <section class="wrapper">
    <div class="contents">5600</div>
  </section>
  <section class="wrapper">
    <div class="contents">5800</div>
  </section>
  <section class="wrapper">
    <div class="contents">6000</div>
  </section>
</div>
.controller {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 1;
  > a {
    display: block;
    text-decoration: none;
    padding: 8px;
    text-align: right;
    background-color: #eee;
    border: 1px solid;
    font-weight: bold;
    color: inherit;
  }
}
.cls-score {
  position: fixed;
  bottom: 0;
  right: 0;
  z-index: 1;
  color: #0000ff;
  font-size: 20px;
  padding: 10px;
  &::before {
    display: inline;
    content: "cls: ";
  }
}

.wrapper {
  content-visibility: auto;
  contain-intrinsic-size: 300px;

  &:nth-child(4n) {
    background-color: rgba(#ff0000, 0.3);
  }
  &:nth-child(4n-1) {
    background-color: rgba(#00ff00, 0.3);
  }
  &:nth-child(4n-2) {
    background-color: rgba(#0000ff, 0.3);
  }
  &:nth-child(4n-3) {
    background-color: rgba(#ffff00, 0.3);
  }
}
.contents {
  height: 200px;
  position: relative;

  > .contents__sub {
    position: absolute;
    top: 100px;
    left: 0;
    right: 0;
    background-color: #fff;
  }
}
View Compiled
const clsDisplayEl = document.querySelector(".js-cls");
let DCLS = 0;
new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    if (entry.hadRecentInput) return; // Ignore shifts after recent input.
    DCLS += entry.value;
    clsDisplayEl.innerText = DCLS.toPrecision(4);
  });
}).observe({ type: "layout-shift", buffered: true });

const swing = (p) => 0.5 - Math.cos(p * Math.PI) / 2;
const scrollToSmoothly = (offset, duration = 500) => {
  const currentPos = window.scrollY;
  let startTime = null;

  const scrollStep = (time) => {
    startTime = !startTime ? time : startTime;
    const progress = Math.min((time - startTime) / duration, 1);
    window.scrollTo(0, currentPos + (offset - currentPos) * swing(progress));
    if (progress < 1) {
      window.requestAnimationFrame(scrollStep);
    } else {
      window.scrollTo(0, offset);
    }
  };

  window.requestAnimationFrame(scrollStep);
};

const scrollLink = document.querySelector(".js-scroll");
scrollLink.addEventListener(
  "click",
  (e) => {
    e.preventDefault();
    const targetId = e.currentTarget.getAttribute("href");
    const targetLink = document.querySelector(targetId);
    const offset = targetLink.getBoundingClientRect().top + window.scrollY;
    scrollToSmoothly(offset, 1000);
  },
  false
);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.