视差效果 - 在滚动时计算父项的子偏移量

时间:2016-09-16 10:12:11

标签: scroll parent offset parallax absolute

我正在尝试创建一个视差效果,这样一个绝对定位的子元素应该以比滚动时父元素慢的速度移动。

孩子将始终是父母的130%身高,但父母可以是任何身高:

HTML:

<div class="parallax-window lg">
  <div class="parallax-image image-1"></div>
  <div class="parallax-content">Hello World</div>
</div>

<div class="parallax-window">
  <div class="parallax-image image-2"></div>
  <div class="parallax-content">Hello World</div>
</div>

CSS:

.parallax-window {
  min-height: 300px;
  position: relative;
  overflow: hidden;
}

.parallax-window.lg {
  min-height: 600px;
}

.parallax-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 130%;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: 50% 50%;
  transform: translate3d(0, 0, 0);
  z-index: -1;
 }

.image-1 {
  background-image: url(https://i.ytimg.com/vi/TbC-vUPMR7k/maxresdefault.jpg);
}

.image-2 {
  background-image: url(https://i.ytimg.com/vi/xi5-YrAEChc/maxresdefault.jpg);
}

我有一个移动图像的公式,但我的数学显然是偏离的:

var win = $(window),
        win_h = win.height(),
        parallaxers = $('.parallax-window');

    function scroll_events() {
        var win_top = win.scrollTop(),
            win_btm = win_top + win_h;
    
        parallaxers.each(function() {
            var cont = $(this),
                cont_top = cont.offset().top,
                cont_h = cont.height(),
                cont_btm = cont_top + cont_h,
                para = cont.find('.parallax-image'),
                para_h = Math.round(cont_h * 1.3);
            if (cont_btm > win_top && cont_top <= win_btm) {
                var diff = (win_h - cont_h) / (win_h - para_h),
                    value = -Math.round((win_top * diff));
                // para.css('transform', 'translate3d(0,' + value*-1 + 'px, 0)');
                para.css('top', value + 'px');
            }
        });
    }

图像移动但速度不正确。

当元素首次进入视口时,图像应与父图像的顶部对齐。然后滚动后,当图像底部到达视口顶部时,图像的底部应与父图像的底部对齐。

任何帮助都会受到大力赞赏!

FIDDLE(https://jsfiddle.net/8dwLwgy7/1/

1 个答案:

答案 0 :(得分:1)

我想出来了。

对于将来磕磕绊绊的人 - 诀窍是将窗口滚动值替换为窗口的剩余部分滚动量减去元素的偏移顶部减去元素的高度。

然后通过将容器高度和元素高度之间的差除以窗口和容器中的最大值来计算速度:

// Wrong:
// value = -Math.round((win_top * diff));

// Right:
var diff = elem_h - cont_h,
    max = Math.max(cont_h, win_h),
    speed = diff / max,
    cont_scrolled = win_top - cont_top - cont_h,
    value = Math.round(cont_scrolled * speed);

para.css('top', value + 'px');

完整的工作代码:

&#13;
&#13;
(function() {
  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
  }
  if (!window.requestAnimationFrame)
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(function() {
          callback(currTime + timeToCall);
        },
        timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame = function(id) {
      clearTimeout(id);
    };
}());


(function($) {

  var win = $(window),
    win_h = win.height();
		parallaxers = $('.parallax-window'),
		parallax_objs = [],
    scroll_busy = false;

	function init_parallax() {
		win_h = win.height();
		parallax_objs = [];
		parallaxers.each(function() {
			var cont = $(this),
				elem = cont.find('.parallax-image'),
				cont_top = cont.offset().top,
				cont_h = cont.height(),
				elem_h = Math.round(cont_h * 1.3),
				diff = elem_h - cont_h,
				max = Math.max(cont_h, win_h),
				speed = diff / max,
				parallaxer = {
					cont_top: cont_top,
					cont_h: cont_h,
					elem: elem,
					speed: speed
				};
			parallax_objs.push(parallaxer);
		});
	}
  
  function on_scroll() {
    if (!scroll_busy) {
      scroll_busy = true;
      window.requestAnimationFrame(init_scroll);
    }
  }

  function init_scroll() {
    scroll_events()
    scroll_busy = false;
  }

  function scroll_events() {
    var win_top = win.scrollTop(),
      win_btm = win_top + win_h;

		$.each(parallax_objs, function(i, para) {
			cont_btm = para.cont_top + para.cont_h;
			if( cont_btm > win_top && para.cont_top <= win_btm ) {
				var cont_scrolled = win_top - para.cont_top - para.cont_h,
					value = Math.round(cont_scrolled * para.speed);
				para.elem.css('top', value + 'px');
			}
		});
  }

  $(document).ready(function() {
  	init_parallax();
    win.resize(init_parallax);
    scroll_events();
    win.scroll(on_scroll);
  });

})(jQuery);
&#13;
.parallax-window {
  min-height: 300px;
  position: relative;
  overflow: hidden;
}

.parallax-window.lg {
  min-height: 600px;
}

.parallax-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 130%;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: 50% 50%;
  transform: translate3d(0, 0, 0);
  z-index: -1;
}

.image-1 {
  background-image: url(https://i.ytimg.com/vi/TbC-vUPMR7k/maxresdefault.jpg);
}

.image-2 {
  background-image: url(https://i.ytimg.com/vi/xi5-YrAEChc/maxresdefault.jpg);
}

.parallax-content {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  text-align: center;
  font-family: arial, sans-serif;
  font-size: 60px;
  color: #fff;
  transform: translateY(-50%);
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="parallax-window lg">
  <div class="parallax-image image-1"></div>
  <div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window">
  <div class="parallax-image image-2"></div>
  <div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window lg">
  <div class="parallax-image image-1"></div>
  <div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window">
  <div class="parallax-image image-2"></div>
  <div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window lg">
  <div class="parallax-image image-1"></div>
  <div class="parallax-content">Hello World</div>
</div>
&#13;
&#13;
&#13;

更新小提琴:https://jsfiddle.net/8dwLwgy7/2/