视差效果-滚动时计算子级到父级的偏移量 [英] Parallax effect - calculate child offset to parent on scroll

查看:58
本文介绍了视差效果-滚动时计算子级到父级的偏移量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建视差效果,以便绝对定位的子元素的移动速度应比滚动时其父元素的移动速度慢.

I'm trying to create a parallax effect whereby an absolutely positioned child element should move at a rate slower than it's parent on scroll.

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

The child will always be 130% height of the parent but the parent can be any height:

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);
}

我有一个公式可以移动图像,但是我的数学显然很不正确:

I have a formula to move the image but my maths is clearly way off:

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');
            }
        });
    }

图像移动但速度不正确.

The images move but not at the correct rate.

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

The image should be in line with the top of the parent when the element first comes into the viewport. Then after scrolling, the bottom of the image should be in line with the bottom of the parent when it reaches the top of the viewport.

任何帮助将不胜感激!

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

推荐答案

我知道了.

对于将来遇到任何麻烦的人-诀窍是将窗口滚动值替换为窗口滚动量的其余部分减去元素的偏移顶部,再减去元素的高度.

For anyone stumbling on this in the future - the trick was to replace the window scrolled value with the remainder of the window scrolled amount minus the element's offset top, minus the height of the element.

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

Then calculate the speed by dividing the difference between the container height and the element height with largest of either the window and the container:

// 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');

完整的工作代码:

(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);

.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%);
}

<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>

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

这篇关于视差效果-滚动时计算子级到父级的偏移量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆