How to increase/decrease opacity for an element scrolling inside a fixed container

Viewed 35

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 Here is an example 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.

0 Answers
Related