I'm trying to recreate an effect similar to this one which I've found on the BBC website with a change which is driving me mad.
Obtaining the same effect as the BBC website it's easy, and I have already replicated it, but what I want to achieve is creating a fade-in and fade-out transition for elements which are scrolling inside the fixed box; Basically, children elements should start from opacity: 0 then change their opacity until opacity: 1 at the scroll's "middle point" and then go back gradually to opacity: 0 when they reach the container's top.
Following here is what I came out with
TL,DR: here is a cleaner example with a fiddle
A simple illustration of what I'm trying to achieve

HTML
<header>
<h2>JS Scroll Stories</h2>
</header>
<main id="wrapper">
<div class="js-story">
<div class="js-story-images">
<div class="images-wrapper">
<img src="https://via.placeholder.com/1440x700" />
<img src="https://via.placeholder.com/1440x700" />
<img src="https://via.placeholder.com/1440x700" />
<img src="https://via.placeholder.com/1440x700" />
<img src="https://via.placeholder.com/1440x700" />
<img src="https://via.placeholder.com/1440x700" />
</div>
</div>
<div class="js-story-elements">
<p>Pellentesque scelerisque velit tortor. Proin.</p>
<p>Quisque eget risus quis libero.</p>
<p>Duis lorem magna, molestie in.</p>
<p>Aliquam commodo convallis tellus, eu.</p>
<p>Phasellus eu gravida est, eu.</p>
<p>Ut non purus neque. Proin.</p>
</div>
</div>
</main>
CSS
div.js-story.fixed-top div.js-story-images {
position: fixed;
top: 0;
bottom: inherit;
width: 100%;
}
div.js-story div.js-story-images {
z-index: -100;
}
div.js-story div.js-story-images div.images-wrapper {
position: relative;
}
div.js-story div.js-story-images div.images-wrapper img {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: 0 auto;
}
div.js-story div.js-story-elements {
width: 100%;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
}
div.js-story div.js-story-elements:before,
div.js-story div.js-story-elements:after {
content: '';
display: block;
position: static;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
}
div.js-story div.js-story-elements p {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin: 0;
opacity: 0;
position: relative;
transition: opacity 300ms ease-in;
background-color: red;
}
Relevant JS
const {
pageYOffset
} = window
// a "storyItem" is the <div class="js-story"> element
// "elements" are the children which are scrolling
const {
wrapper,
elements
} = storyItem;
const {
classList,
offsetTop
} = wrapper;
if (classList.contains(this.fixedElementClass)) {
const totalOffset = pageYOffset - offsetTop;
elements.forEach((item) => {
const {
offsetTop,
clientHeight
} = item
const [start, middle, end] = [
offsetTop,
(offsetTop + clientHeight / 2),
(offsetTop + clientHeight)
]
let setOpacity = 0;
if (totalOffset < start || totalOffset > end) {
setOpacity = 0;
} else {
setOpacity = (clientHeight * 2 - totalOffset) / clientHeight;
}
console.log(`Set opacity: ${setOpacity}`);
item.style.opacity = setOpacity;
})
}
But I'm only getting a strange behavior on opacity, which goes from 0 to 0.7 and basically gets stuck.