Effect on horizontal scroll

Viewed 95

I created this horizontal scroll using only CSS (working only on Chrome because of the scroll style).

* {
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  font-family: 'Nunito', sans-serif;
}

::-webkit-scrollbar {
  height: 0;
  width: 0;
}

::-webkit-scrollbar-button {
  height: 0;
  width: 0;
}

h2 {
  margin: 0;
}

p {
  font-size: 1.25em;
  letter-spacing: 0.56px;
  line-height: 32px;
}

.container {
  background-color: #000;
  bottom: 0;
  height: 100vh;
  left: 0;
  margin: auto;
  position: absolute;
  right: 0;
  top: 0;
  width: 100vw;
}

.horScroll {
  background-color: #abc;
  height: 100vw;
  overflow-x: hidden;
  overflow-y: auto;
  position: absolute;
  -ms-scroll-snap-type: mandatory;
  scroll-snap-type: mandatory;
  -ms-scroll-snap-points-y: repeat(100vw);
  scroll-snap-points-y: repeat(100vw);
  -ms-scroll-snap-type: y mandatory;
  scroll-snap-type: y mandatory;
  -webkit-transform: translateX(-100%) rotate(-90deg);
  -ms-transform: translateX(-100%) rotate(-90deg);
  transform: translateX(-100%) rotate(-90deg);
  -webkit-transform-origin: top right;
  -ms-transform-origin: top right;
  transform-origin: top right;
  width: 100vh;
}

.item {
  background-color: #e4e4e4;
  height: 100vw;
  position: -webkit-sticky;
  position: sticky;
  scroll-snap-align: start;
  top: 0;
  width: 100vh;
}

.horScroll > div:nth-of-type(2n) {
  background-color: #333;
  color: #fff;
}

.item-inner {
  height: 100vh;
  max-height: 100vh;
  overflow: scroll;
  padding: 40px;
  -webkit-transform: rotate(90deg) translateX(-100vh);
  -ms-transform: rotate(90deg) translateX(-100vh);
  transform: rotate(90deg) translateX(-100vh);
  -webkit-transform-origin: bottom left;
  -ms-transform-origin: bottom left;
  transform-origin: bottom left;
  width: 100vw;
}
.item-content {
  height: 100%;
}
<div class="container">
  <div class="horScroll">
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 1</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 2</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 3</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 4</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 5</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 6</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

It works as expected. Now I'm trying to create an extra effect in JavaScript.

I want that when the next item is coming, there will be a change in opacity, scale or similar effect on the previous item showing that it is "fading out". It is a transition effect between two items. In this case I'm trying opacity.
In the reverse direction the opposite will happen: a "fade in" on the item that had disappeared.

Inside the forEach() loop I could identify what item is being scrolled at the moment (as you can check in the console.log), but now I'm not getting the opacity calculation right. I have a few factors to consider like the current item and current scroll position.

var widthBase = window.innerWidth;
window.addEventListener("resize", function() {
  widthBase = window.innerWidth;
})

var items = document.querySelectorAll(".item");

document.querySelector(".horScroll").addEventListener("scroll", function(e) {

  items.forEach(function(item, i) {

    var currentScroll = e.target.scrollTop;

    if (currentScroll >= widthBase * (i) && currentScroll < widthBase * (i + 1)) {
      console.log("item index: " + i + ", scroll position: " + currentScroll);
      // item.querySelector(".item-content").style.opacity = ? // opacity calculation value
    }

  })

})

I've tried item.querySelector(".item-content").style.opacity = (widthBase * (i + 1))/currentScroll - 1, but it works partially. Some other variations also failed. I'm missing something.

In addition, I think that a loop through all the items in each scroll is not performative, but I couldn't think of anything different.

1 Answers

I fixed the calculation. First, I had to consider this:

Top position of item is equal to 1.
Bottom position of item is equal to 0.001.
So, current scroll will be X, the value I need for each scroll.

1 and 0.001 are the opacity, transform: scale() or another property with value between 0 and 1.
It must be 0.001 instead of 0, otherwise the calculation will fail. "Top position" also must not be 0, so I will always add 1 to it.

Calculation.

Now, using scale instead of opacity, the result would be:

"scale(" + (1 - (currentScroll-((widthBase * i) + 1))*(1-0.55)/(((widthBase * (i + 1)) + 1)-((widthBase * i) + 1))) + ")";

Working snippet:

var widthBase = window.innerWidth;
window.addEventListener("resize", function() {
  widthBase = window.innerWidth;
})

var items = document.querySelectorAll(".item");

document.querySelector(".horScroll").addEventListener("scroll", function(e) {

  items.forEach(function(item, i) {

    var currentScroll = e.target.scrollTop;

    if (currentScroll > widthBase * (i) && currentScroll < widthBase * (i + 1)) {      
      item.querySelector(".item-content").style.transform = "scale(" + (1 - (currentScroll-((widthBase * i) + 1))*(1-0.55)/(((widthBase * (i+1)) + 1)-((widthBase * i) + 1))) + ")";
    }

  })

})
* {
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  font-family: 'Nunito', sans-serif;
}

::-webkit-scrollbar {
  height: 0;
  width: 0;
}

::-webkit-scrollbar-button {
  height: 0;
  width: 0;
}

h2 {
  margin: 0;
}

p {
  font-size: 1.25em;
  letter-spacing: 0.56px;
  line-height: 32px;
}

.container {
  background-color: #000;
  bottom: 0;
  height: 100vh;
  left: 0;
  margin: auto;
  position: absolute;
  right: 0;
  top: 0;
  width: 100vw;
}

.horScroll {
  background-color: #abc;
  height: 100vw;
  overflow-x: hidden;
  overflow-y: auto;
  position: absolute;
  -ms-scroll-snap-type: mandatory;
  scroll-snap-type: mandatory;
  -ms-scroll-snap-points-y: repeat(100vw);
  scroll-snap-points-y: repeat(100vw);
  -ms-scroll-snap-type: y mandatory;
  scroll-snap-type: y mandatory;
  -webkit-transform: translateX(-100%) rotate(-90deg);
  -ms-transform: translateX(-100%) rotate(-90deg);
  transform: translateX(-100%) rotate(-90deg);
  -webkit-transform-origin: top right;
  -ms-transform-origin: top right;
  transform-origin: top right;
  width: 100vh;
}

.item {
  background-color: #e4e4e4;
  height: 100vw;
  position: -webkit-sticky;
  position: sticky;
  scroll-snap-align: start;
  top: 0;
  width: 100vh;
}

.horScroll > div:nth-of-type(2n) {
  background-color: #333;
  color: #fff;
}

.item-inner {
  height: 100vh;
  max-height: 100vh;
  overflow: scroll;
  padding: 40px;
  -webkit-transform: rotate(90deg) translateX(-100vh);
  -ms-transform: rotate(90deg) translateX(-100vh);
  transform: rotate(90deg) translateX(-100vh);
  -webkit-transform-origin: bottom left;
  -ms-transform-origin: bottom left;
  transform-origin: bottom left;
  width: 100vw;
}
.item-content {
  height: 100%;
}
<div class="container">
  <div class="horScroll">
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 1</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 2</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 3</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 4</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 5</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
    <div class="item">
      <div class="item-inner">
        <div class="item-content">
          <h2>Item 6</h2>
          <div>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad tempora ducimus tenetur facilis magnam assumenda atque? Minus molestiae hic consectetur voluptatibus maxime, a eum laudantium explicabo similique, iure dignissimos quae.</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Unfortunately, I didn't change the iteration on each scroll, which affects the performance a little bit.

Related