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.