Home > Back-end >  Full height sticky horizontal scroll slider
Full height sticky horizontal scroll slider

Time:09-21

I am trying to create a smooth scrolling horizontal slider animation inspired by the one here https://weltio.com/

As visible in weltio, as you scroll you get a sticky smooth slider of images and content inside.

My page is filled with content and what I would like to achieve is that once that section is scrolled to, I want the div to occupy the screen and as you scroll down it changes the content.

-------------------------------------------------------------------------------

I have been looking for videos and examples for so long and I can't seem to achieve that desired, smooth sticky animated design I am looking for because I can't seem to find any similar examples I can use online.

This is the last solution I came to but it still does not look smooth as the user can sense the scroll on the page where as I want it to be sticky in place and give that same smooth effect demonstrated in weltio.

.contain {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: auto;
  scroll-behaviour: smooth;
  scroll-snap-type: y mandatory;
}

.sec {
  position: relative;
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: centre;
  background: #f00;
  scroll-snap-align: center;
  background-attachment: fixed;
  background-size: cover;
  background-position: center;
  background-blend-mode: multiply;
}

h3 {
  color: #ffffff;
  font-size: 10vw;
  text-align: center;
  margin: 0 50px;
}

.sec:nth-child(1) {
  background: #f00 url(./big-bgr.png);
}

.sec:nth-child(2) {
  background: #0f0 url(./big-bgr.png);
}

.sec:nth-child(3) {
  background: #ff0 url(./big-bgr.png);
}

.sec:nth-child(4) {
  background: #f436ee url(./big-bgr.png);
}

.sec:nth-child(5) {
  background: #00f url(./big-bgr.png);
}

.content {
  position: absolute;
  top: 0;
  width: 100%;
  text-align: center;
}

.content h2 {
  position: relative;
  display: flex;
  justify-content: center;
}

.content h2 span {
  position: sticky;
  top: 0;
  line-height: 100vh;
  height: 100vh;
  color: #ffffff;
  font-size: 14vw;
  margin-top: calc(100vh * var(--i));
}
<div >
  <div >
    <div >
      <h3>Scroll Down</h3>
    </div>
    <div ></div>
    <div ></div>
    <div ></div>
    <div ></div>

    <div >
      <h2>
        <span style="--i:1;">T</span>
        <span style="--i:2;">E</span>
        <span style="--i:3;">S</span>
        <span style="--i:4;">T</span>
      </h2>
    </div>
  </div>
</div>

CodePudding user response:

Effect you are looking for is not achievable with HMTL and CSS only.

What Weltio does is they scroll all the content with transform: translate3d() and smooth out scrolling position in JavaScript (a smooth in out kind of situation).

So what you need to do to get same scrolling as Weltio is first disable native scrolling with overflow: hidden on body element.

Second you need to listen to user scrollwheel input and remember how much he has scrolled. window.addEventListener("wheel", event => desiredScroll = event.deltaY);. (Touch devices need to be handled separately)

And then finally you need to update your actualScroll value over time to smoothly come closer to desiredScroll. You can use for example requestAnimationFrame for that

let desiredScroll = 0;
let actualScroll = 0;

function updateScroll() {
  const delay = 10;
  actualScroll = actualScroll   (desiredScroll - actualScroll) / delay;
  
  updateTransform();
  
  window.requestAnimationFrame(updateScroll);
}

const elements = [...document.getElementsByClassName('element')]

function updateTransform() {
  //instead of moving all elements you might want to just translate body or parent div of all elements
  elements.forEach(element => element.style.transform = `translateY(${actualScroll}px)`)
}

window.addEventListener("wheel", event => desiredScroll  = event.deltaY);

window.requestAnimationFrame(updateScroll);
html, body {margin: 0; padding: 0;}

html {
background-color: #334499;
}

body {
  overflow:hidden;
  min-height: 100vh;
}

.element {
  height: 300px;
  background-color: #112233;
  margin: 20px;
  border-radius: 20px;
}
<html>

<body>
  <div id="element" ></div>
  <div ></div>
  <div ></div>
  <div ></div>
</body>

</html>

Now you have the base. Next steps would be to add scroll stop so that scroll does't go under 0 and over whole content height. You could even add fancy rubber band effect like on iPhones where you allow scroll go past 0 but x2 slower and then it bounces back.

let desiredScroll = 0;
let actualScroll = 0;

function updateScroll() {
  const delay = 10;
  const maxScrollHeight = document.body.clientHeight - window.innerHeight;
  
  if(desiredScroll < 0) desiredScroll -= desiredScroll / (delay / 2)
  if(desiredScroll > maxScrollHeight) desiredScroll -= (desiredScroll - maxScrollHeight) / (delay / 2)
  
  actualScroll = actualScroll   (desiredScroll - actualScroll) / delay;
  if(Math.abs(actualScroll - desiredScroll) < 1) actuallScroll = desiredScroll;
  
  updateTransform();
  
  window.requestAnimationFrame(updateScroll);
}

function updateTransform() {
  document.body.style.transform = `translateY(${-actualScroll}px)`;
}

window.addEventListener("wheel", event => {

const scroll = event.deltaY;
if(desiredScroll < 0 && scroll < 0) desiredScroll  = scroll / 2;
else if(desiredScroll > (document.body.clientHeight - window.innerHeight) && scroll > 0) desiredScroll  = scroll / 2;
else desiredScroll  = scroll;
});

window.requestAnimationFrame(updateScroll);
html, body {margin: 0; padding: 0;}

html {
background-color: #334499;
}

body {
  overflow:hidden;
  min-height: 100vh;
  padding: 20px 0
}

.element {
  height: 300px;
  background-color: #112233;
  margin: 20px;
  border-radius: 20px;
}
<html>

<body>
  <div id="element" ></div>
  <div ></div>
  <div ></div>
  <div ></div>
</body>

</html>

Now you have smooth scrolling system. All left to do is add snapping points to it. For example easiest way would be to make all elements same height as screen (or not) and with each scroll either try to snap to nearest element or scroll 1 element worth of distance with each wheel movement and use cooldown which will not allow scrolling until animation is done.

  • Related