首页 > 解决方案 > 当元素在视口中时开始视差

问题描述

我在一个对多个元素(文本、图像等)具有视差效果的网站上工作。当元素位于视口底部时,我需要启动视差效果。

在这种情况下,元素距离页面顶部 3000 像素,当元素在视口中时,我想将 window.pageYOffset 重置为零(或类似的东西),这种效果是有意义的。

此代码有效但不好,当我更改分隔符高度时,视差效果的起始位置不同。您可以尝试将 css 中的分隔符高度更改为 500px 和 5000px。

有什么更好的解决方案?

谢谢

这是小提琴:https ://jsfiddle.net/you8c6d7/

function parallax(element, delay) {
  var start = document.querySelector(element).getBoundingClientRect().top;
  var px = window.pageYOffset - (start * 2 + window.innerHeight);
  var elClass = document.querySelector(element);

  elClass.style.transform = 'translateY(' + '-' + px / delay + 'px' + ')';
};

window.addEventListener('scroll', function() {
  parallax('.box', 5);
});
body {
  height: 6000px;
  margin 0;
}

.box {
  background: blue;
  width: 300px;
  height: 300px;
}

.separator {
  height: 500px;
  background: grey;
}
<div class="separator"></div>
<div class="box"></div>

标签: javascript

解决方案


这是使用Intersection Observer API的片段。

我使用了实验功能 "IntersectionObserver.thresholds",因此IE 不支持

根据您的目标受众,您可能需要使用polyfill

该脚本观察目标框是否与视口相交,并根据框/视口的比例对其进行变换。有关更多详细信息,请参阅代码中的注释和 JSDoc。

/**
 * Creates an IntersectionObserver and starts observing all elements found using the selector.
 *
 * @param {String} selector: Selector used to find all target elements
 * @param {Number[]} threshold: Array of intersection ratios, at which the callback is executed
 * @param {Function} callback: Callback executed for each threshold
 */
function observe(selector, threshold, callback) {
  const elements = document.querySelectorAll(selector);
  const options = {
    rootMargin: '0px',
    threshold: threshold,
  };

  const observer = new IntersectionObserver(callback, options);

  for (const element of elements) {
    observer.observe(element);
  }
}

/**
 * Creates a CSS translateY value.
 *
 * @param {Number} ratio: A number between 0 and 1
 * @param {String} total: A valid CSS number and unit (10px, 100%, 30vh, …)
 * @return {String} The CSS translateY value.
 */
function translateY(ratio, total) {
  return `translateY(calc(-${ratio} * ${total})`;
}

/**
 * Callback executed for the box elements
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
 *
 * @param {IntersectionObserverEntry[]} entries: Intersection Observer Entries
 * @param {IntersectionObserver} observer: Intersection Observer
 */
function boxParallax(entries, observer) {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      entry.target.style.transform = translateY(entry.intersectionRatio, '20%');
    }
  }
}

/**
 * Create one threshold for each intersection ratio.
 *
 * @return {Number[]}
 */
function createThreshold() {
  const threshold = [];
  for (let i = 0; i <= 1.0; i += 0.01) {
    threshold.push(i);
  }

  return threshold;
}

const threshold = createThreshold();
observe('.box', threshold, boxParallax);
body {
  height: 6000px;
  margin 0;
}

.box {
  background: blue;
  width: 300px;
  height: 300px;
}

.separator {
  height: 500px;
  background: grey;
}
<div class="separator"></div>
<div class="box"></div>


推荐阅读