0

I have some code for a specific timeline, the problem is : the background item in the timeline does not show up at the right time when scroll (top and bottom)

I need te display the bg when the concerned item is centred vertically, here for example, there is a display offset in the last and penultimate background.

Please take a look to the GIF : https://gfycat.com/possiblesadcowbird

JS code (i took it from : https://codepen.io/knyttneve/pen/bgvmma?editors=0010 and edited it according to my project) :

var fn_timeline = function() {
  $.fn.timeline = function() {
    var selectors = {
      id: $(this),
      item: $(this).find(".timeline-item"),
      activeClass: "timeline-item--active",
      img: ".o-timeline__img > img"
    };
    selectors.item.eq(0).addClass(selectors.activeClass);
    selectors.id.css("background-image", "url(" + selectors.item.first().find(selectors.img).attr("src") + ")");

    var itemLength = selectors.item.length;
    $(window).scroll(function() {
      var max, min;
      var pos = $(this).scrollTop();
      selectors.item.each(function(i) {
        min = $(this).offset().top;
        max = ($(this).height() + $(this).offset().top);
        var that = $(this)
        if (i == itemLength - 2 && pos > min + $(this).height() / 2) {
          selectors.item.removeClass(selectors.activeClass);
          selectors.id.css("background-image", "url(" + selectors.item.last().find(selectors.img).attr('src') + ")");
          selectors.item.last().addClass(selectors.activeClass)
        } else if (pos <= max - 40 && pos >= min) {
            selectors.id.css("background-image", "url(" + $(this).find(selectors.img).attr('src') + ")");
            selectors.item.removeClass(selectors.activeClass);
            $(this).addClass(selectors.activeClass);
          }
      });
    });
  }
  $("#timeline-1").timeline();
}

HTML code:

<div class="timeline-wrapper  container-content container-content--smaller container-content--fake-col   timeline1col  ">
  <div class="timeline-container" id="timeline-1" style="background-image: url(&quot;img/tl-3.jpg&quot;);">
    <div class="timeline">
      <div id="fullpage">
        <div class="section timeline-item-wrapper timeline-item">
          <div class="timeline-marker"></div>
          <div class="timeline__content">
            <div class="timeline-minature">
              <div class="o-timeline__img timeline-img">
                <img src="img/tl-1.jpg" style="width: 350px">
              </div>
            </div>

            <h2 class="timeline__content-title">Le premier ordinateur</h2>

            <div class="wysiwyg">
              He was born in 1881 (probably in the spring) in Salonica, then an Ottoman city, now inGreece. His father Ali Riza, a customs official turned lumber merchant, died when Mustafawas still a boy. His mother Zubeyde, adevout and strong-willed woman, raised him and his sister.
            </div>

            <a href="#" class="a-link--border-effect timeline-link">
              * Qu’est-ce que la géodésie ?
            </a>
          </div>
        </div>
        <div class="section timeline-item-wrapper timeline-item">
          <div class="timeline-marker"></div>
          <div class="timeline__content">
            <div class="timeline-minature">
              <div class="o-timeline__img timeline-img">
                <img src="img/tl-2.jpg" style="width: 350px">
              </div>
            </div>

            <p class="timeline__content-date">1991</p>

            <div class="wysiwyg">
              He was born in 1881 (probably in the spring) in Salonica, then an Ottoman city, now inGreece. His father Ali Riza, a customs official turned lumber merchant, died when Mustafawas still a boy. His mother Zubeyde, adevout and strong-willed woman, raised him and his sister.
            </div>

          </div>
        </div>
        <div class="section timeline-item-wrapper timeline-item timeline-item--active">
          <div class="timeline-marker"></div>
          <div class="timeline__content">
            <div class="timeline-minature">
              <div class="o-timeline__img timeline-img">
                <img src="img/tl-3.jpg" style="width: 350px">
              </div>
            </div>

            <h2 class="timeline__content-title">Le premier ordinateur</h2>

            <div class="wysiwyg">
              He was born in 1881 (probably in the spring) in Salonica, then an Ottoman city, now inGreece. His father Ali Riza, a customs official turned lumber merchant, died when Mustafawas still a boy. His mother Zubeyde, adevout and strong-willed woman, raised him and his sister.
            </div>

            <a href="#" class="a-link--border-effect timeline-link">
              * Qu’est-ce que la géodésie ?
            </a>
          </div>
        </div>
        <div class="section timeline-item-wrapper timeline-item">
          <div class="timeline-marker"></div>
          <div class="timeline__content">
            <div class="o-timeline__img timeline-bg">
              <img src="img/tl-4.jpg" alt="">
            </div>

            <h2 class="timeline__content-title">just bg</h2>

            <div class="wysiwyg">
              He was born in 1881 (probably in the spring) in Salonica, then an Ottoman city, now inGreece. His father Ali Riza, a customs official turned lumber merchant, died when Mustafawas still a boy. His mother Zubeyde, adevout and strong-willed woman, raised him and his sister.
            </div>

          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
  • what is wrong with background-attachment: fixed; like this: https://www.w3schools.com/howto/tryhow_css_parallax_demo.htm – noshad b.e Jan 13 '21 at 11:09
  • Hi, thank you for your comment, but it doesn't fit with what i did..i have to change all the css, and js, I don't have time :( – meryem mereyemm Jan 13 '21 at 11:17
  • You'll want to add image preloading as well. https://stackoverflow.com/questions/3646036/preloading-images-with-javascript – Daniel Beck Jan 13 '21 at 22:34

1 Answers1

0

That is a mix of Math and UX design issue. (exactly the kind of problem I like!)

First, you have to consider is the user is scrolling up or down. That is the key.
Depending on the scroll direction, you will check the position of the top OR bottom of the item.

For example, if you only compare the top of the item, the user will have to scroll up the whole item until the top crosses the middle before it unblurs. That's a no-go.

So that really is about the user experience aspect: When the user is scrolling down (so the content moves up), he needs the next item to show at "some point". Because he may still be reading the text below the image, I think that "point" is a bit above the middle of the viewport... But not too high.

When the user is scrolling up (so the content moves down), he certainly want to have what is coming from above to unblur way before the middle of the viewport.

So... You have two different viewport positions to take in account. I call those points "trigger" thereafter.

  • a bit above the middle (scrolling down)
  • a bit below the top (scrolling up)

===========

So that is getting complex...
   Two scroll directions and two viewport positions to compare with the top OR the bottom of the item.

So I made up two variables to hold a condition results based on 4 aspects:

  1. scrolling up or down
  2. scrolled pixels are less than the top OR bottom of item
  3. the "trigger" is greater than the top of the item
  4. the "trigger" + 20px is less than the bottom of the item (that is to avoid flickering... Remember you are in a loop)

And I defined the two "viewport positions" as 5/16 and 3/16...
But you may perfer some values in percentage, like 0.31 and 0.19... You to play with it.

(function ($) {
  $.fn.timeline = function () {
    var selectors = {
      id: $(this),
      item: $(this).find(".timeline-item"),
      activeClass: "timeline-item--active",
      img: ".timeline__img"
    };

    // Onload, set first item as active
    selectors.item.eq(0).addClass(selectors.activeClass);

    // The viewport height
    var winHeight = $(window).height();

    // For the scrolling direction
    var lastPos = 0;

    // Scroll event handler
    $(window).scroll(function () {
      var item_bottom,
        item_top,
        item_height,
        scrollDown,
        trigger_top,
        trigger_bottom;

      // The window scrolled pixels
      var pos = $(this).scrollTop();

      // Scroll direction
      // true: user is scrolling down
      // false: user is scrolling up
      scrollDown = pos > lastPos;

      // items loop
      selectors.item.each(function (i) {
        var this_item = $(this);
        item_top = this_item.offset().top;
        item_height = this_item.height();
        item_bottom = item_height + this_item.offset().top;

        // You can play with those triggers...
        trigger_top = pos + (5 / 16) * winHeight;
        trigger_bottom = pos + (3 / 16) * winHeight;

        // Just for the console.log
        var item_date = this_item.find(".timeline__content-title").text();

        // The conditions
        var scroll_down_condition =
          scrollDown &&
          pos < item_top &&
          trigger_top >= item_top &&
          trigger_top + 20 <= item_bottom;

        var scroll_up_condition =
          !scrollDown &&
          pos < item_bottom &&
          trigger_bottom >= item_top &&
          trigger_bottom + 20 <= item_bottom;

        // If one or the other condition is true
        // Unblur the item and set the background
        if (scroll_down_condition || scroll_up_condition) {
          console.log(
            `Date ${item_date} is in view - `,
            `Scrolling ${scrollDown ? "down" : "up"}`
          );

          // Set background
          selectors.id.css(
            "background-image",
            "url(" + this_item.find(selectors.img).attr("src") + ")"
          );

          // Remove the active class (unblur) on all items
          selectors.item.removeClass(selectors.activeClass);

          // Unblur
          this_item.addClass(selectors.activeClass);
        }
      }); // END item each

      // For the scrolling direction
      lastPos = pos;
    });
  };
})(jQuery);

CodePen

Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64