视差滚动问题 - 在 webkit 浏览器中滚动时 div 元素抖动
Posted
技术标签:
【中文标题】视差滚动问题 - 在 webkit 浏览器中滚动时 div 元素抖动【英文标题】:parallax scrolling issue - div element jerking when scrolling in webkit browsers 【发布时间】:2012-11-06 14:15:51 【问题描述】:我创建了一个视差滚动,它在 Firefox 中似乎运行良好,但在 chrome 浏览器中滚动时正文文本略有跳跃。 click here scroll to the about section。我不确定这是 css 还是 JS 问题.. 下面是我已合并到视差函数中的 sn-p
有谁知道我如何解决这个问题?
$(document).ready(function()
// Cache the Window object
$window = $(window);
// Cache the Y offset and the speed of each sprite
$('[data-type]').each(function()
$(this).data('offsetY', parseInt($(this).attr('data-offsetY')));
$(this).data('Xposition', $(this).attr('data-Xposition'));
$(this).data('speed', $(this).attr('data-speed'));
);
// For each element that has a data-type attribute
$('[data-type="background"]').each(function()
// Store some variables based on where we are
var $self = $(this),
offsetCoords = $self.offset(),
topOffset = offsetCoords.top;
// When the window is scrolled...
$(window).scroll(function()
// If this section is in view
if ( ($window.scrollTop() + $window.height()) > (topOffset) &&
( (topOffset + $self.height()) > $window.scrollTop() ) )
// Scroll the background at var speed
// the yPos is a negative value because we're scrolling it UP!
var yPos = -($window.scrollTop() / $self.data('speed'));
// If this element has a Y offset then add it on
if ($self.data('offsetY'))
yPos += $self.data('offsetY');
// Put together our final background position
var coords = '50% '+ yPos + 'px';
// Move the background
$self.css( backgroundPosition: coords );
$('[data-type="scroll-text"]', $self).each(function()
var $text= $(this);
var pos = ($window.scrollTop()/10) * $text.data('speed');
var curP = $text.css('margin-top');
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if(is_chrome)
$text.animate(
paddingTop: pos,
, 200, 'linear', function()
// Animation complete.
);
else
$text.css('padding-top', pos);
);
; // in view
); // window scroll
); // each data-type
); // document ready
【问题讨论】:
您的代码将受益于简单的优化:1) 仅调用一次$(window).scrollTop()
并缓存该值,2) 在事件侦听器之外查询 DOM 以获取 [data-text]
元素。
@IanKuca 能否详细说明一下,甚至可以在 github 上编辑 JS。我不是最擅长 javascript 的人
pastebin.com/JCaA7T6A
@IanKuca 使用该脚本我收到以下错误消息...“未捕获的 ReferenceError:$self 未定义”
您需要在我编辑的部分代码之前定义$self
变量。想一想。
【参考方案1】:
一些建议:
1.) 使用position: fixed
避免任何抖动,因为您将从文档流中取出元素。然后,您可以使用 z-index 定位它。
2.) 尽可能多地缓存以缩短处理时间。
3.) Math.round 可能不是必需的,但尝试将此 CSS 添加到您的移动区域:-webkit-transform: translate3d(0,0,0);
这将强制 Chrome 中的硬件加速,这可能会缓解一些抖动。 (当我用 Inspector 添加它时,它在我的屏幕上看起来更流畅,但它并没有摆脱滚轮的跳跃。)注意:不要在整个文档(例如 body 标签)上这样做,因为它可能导致您当前的布局出现一些问题。 (例如,您的导航栏没有固定在窗口顶部。)
4.) 如果您有任何动画作为视差逻辑的一部分运行(将边距补间到适当的位置或沿着这些线的东西),请将其删除 - 这可能会导致您看到的跳跃。
希望这会有所帮助。祝你好运。
【讨论】:
不确定它是否重要,但是,由于问题是询问“webkit”浏览器 - ios Safari 和 android Chrome 都无法处理 position: fixed。不确定移动设备是否重要,但它们是 webkit 浏览器。 iOS 5 和 6 稍微好一点,但 iOS 4 和最新的 Android 对位置固定的处理很差 我遇到了抖动问题,并且 position:fixed 对我有用。谢谢! 我遇到了仅在 Chrome (Win7) 中出现的视差滚动相关问题。我的元素被重新定位'onscroll'并且一切都正确调整,但是当我使用鼠标滚轮滚动时 - 并且只能使用鼠标滚轮 - 视口的整个顶部/底部边缘会跳跃大约 100px 并显示看起来就像浏览器窗口内没有内容的透明区域(你知道,那个灰色/白色方格图案)。这个小故障会迅速重复...您将-webkit-transform: translate3d(0,0,0);
添加到移动元素的建议解决了我的问题。【参考方案2】:
我在 FireFox 和 Chrome (Mac) 中看到了同样的抖动。看着你的容器,让我眼前一亮的一件事是正在计算/使用的像素位置。
Chrome: <div id="about-title" style="margin-top: 1562.3999999999999px;">
FireFox: <div id="about-title" style="margin-top: 1562.4px;">
浏览器不允许内容位于 1/2 像素,更不用说 0.3999999 像素了。我认为它正在移动它,并试图计算是向上舍入还是向下舍入。它会抖动,因为它在每次点击鼠标滚轮时都在计算。
因此,我会尝试将 Math.round() 添加到您的位置,这样容器就不会被搁置。
看看这里的代码:http://webdesigntutsplus.s3.amazonaws.com/tuts/338_parallax/src/index.html
Firebug 一些元素,您会看到它们唯一的像素分数是“0.5”。它们中的大多数(大部分)都是整数值。
【讨论】:
如果您真的快速向上滚动并“卡住”到顶部,我会遇到一个问题,即某些元素会不同步并且可能会偏离数百个像素。这完美地解决了这个问题!谢谢!【参考方案3】:您将不得不更改滚动的工作方式(即更改间距的计算方式),但这可以通过将position:fixed
CSS 元素添加到正在滚动的页面元素来解决。问题在于 JavaScript 处理和渲染所花费的时间。
例如,在您的页面上,您可以将每个包含文本的 <div>
标记设置为具有固定位置,然后使用 JavaScript/JQuery 函数更新 top:
CSS 元素。这应该使页面滚动顺畅。
【讨论】:
【参考方案4】:您是否尝试在滚动功能中添加 preventdefault?
$(window).scroll(function(e)
e.preventDefault();
// rest of your code
【讨论】:
【参考方案5】:在上一个问题中,我创建了一个相当不错的视差滚动实现。 Jquery Parallax Scrolling effect - Multi directional你可能会发现它很有用。
这是 JSFiddle http://jsfiddle.net/9R4hZ/40/ 使用向上/向下箭头或滚轮。
使用填充和边距进行定位可能是您遇到渲染问题的原因。虽然我的代码使用滚动或键盘输入来实现效果,但您可以循环相关部分并检查 $moving 变量,直到您到达屏幕上所需的元素。
function parallaxScroll(scroll)
// current moving object
var ml = $moving.position().left;
var mt = $moving.position().top;
var mw = $moving.width();
var mh = $moving.height();
// calc velocity
var fromTop = false;
var fromBottom = false;
var fromLeft = false;
var fromRight = false;
var vLeft = 0;
var vTop = 0;
if($moving.hasClass('from-top'))
vTop = scroll;
fromTop = true;
else if($moving.hasClass('from-bottom'))
vTop = -scroll;
fromBottom = true;
else if($moving.hasClass('from-left'))
vLeft = scroll;
fromLeft = true;
else if($moving.hasClass('from-right'))
vLeft = -scroll;
fromRight = true;
// calc new position
var newLeft = ml + vLeft;
var newTop = mt + vTop;
// check bounds
var finished = false;
if(fromTop && (newTop > t || newTop + mh < t))
finished = true;
newTop = (scroll > 0 ? t : t - mh);
else if(fromBottom && (newTop < t || newTop > h))
finished = true;
newTop = (scroll > 0 ? t : t + h);
else if(fromLeft && (newLeft > l || newLeft + mw < l))
finished = true;
newLeft = (scroll > 0 ? l : l - mw);
else if(fromRight && (newLeft < l || newLeft > w))
finished = true;
newLeft = (scroll > 0 ? l : l + w);
// set new position
$moving.css('left', newLeft);
$moving.css('top', newTop);
// if finished change moving object
if(finished)
// get the next moving
if(scroll > 0)
$moving = $moving.next('.parallax');
if($moving.length == 0)
$moving = $view.find('.parallax:last');
else
$moving = $moving.prev('.parallax');
if($moving.length == 0)
$moving = $view.find('.parallax:first');
// for debug
$('#direction').text(scroll + " " + l + "/" + t + " " + ml + "/" + mt + " " + finished + " " + $moving.text());
【讨论】:
【参考方案6】:可能与您的具体情况无关,但我遇到了一个跳跃的视差滚动问题,我能够为页面的固定部分添加以下 CSS 来解决它:
@supports (background-attachment: fixed)
.fixed-background
background-attachment: fixed;
不确定所有细节,但可以在 Alternate Fixed & Scroll Backgrounds 找到
【讨论】:
以上是关于视差滚动问题 - 在 webkit 浏览器中滚动时 div 元素抖动的主要内容,如果未能解决你的问题,请参考以下文章