javascript - 视差-元素毛刺

标签 javascript html css parallax

因此,我一直在努力围绕这种名为“视差”的整洁效果。基本上,背景滚动比前景元素慢。

我发现这个新的“技巧”正在起作用。随着滚动的进行,更改top属性以创建视差效果。

问题...

因此,为了提高性能并减轻元素不在用户视口内时CPU的负担,我创建了if语句,该语句检查top位置是否大于300px。如果是,它将覆盖所有内容并将top属性设置回0,因此它将无缘无故地不断增加。

现在,只需滚动一下。看到红色的div越过白色的时,白色的结巴怎么办?在DOM检查器中查看,我发现if语句很奇怪,将top属性设置为0px,即使它不超过300px。快点

在此期间,我很乐意看到有关视差效果的更多建议。我已经看到了有关此效果的一些答案,但它们似乎……对我来说过于复杂。我知道有更好的方法可以做到这一点,我知道有。

而且,如果没有jQuery答案,将不胜感激。谢谢。



var txtfirst = document.getElementById("txtfirst");


window.onscroll = function(){
	var ypos = window.pageYOffset;
  txtfirst.style.top = ypos * 0.4 + "px";


if(txtfirst.style.top > '300px'){
	txtfirst.style.top = '0px';
}
}

html, body {
 margin: 0;
 padding: 0;
 width: 100%;
 height: 100%;
}

.text-first {
  display: flex;
  text-align: center;
  justify-content: center;
  align-items: center;
  font-size: 32px;
  font-family: Arial;
  color: gray;
  width: 100%;
  height: 500px;
  position: relative;
}

.foreground-red {
  width: 100%;
  height: 600px;
  background-color: red;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: Arial;
  color: gray;
  font-size: 32px;
}

.spacer { /*for scrolling purposes*/
  width: 100%;
  height: 1000px;
}

<div class="text-first" id="txtfirst">THIS IS SOME TEXT</div>
<div class="foreground-red">THIS SHOULD GO ABOVE</div>
<div class="spacer"></div>

最佳答案

您的应用程序很有可能(我假设您仅提供了选定的代码片段)无法正常工作,至少是因为您要比较数字时正在比较文本,以进行优化:

txtfirst.style.top > '300px'


上面的行为不会像您期望的那样。 Element::style属性的每个属性(例如您的情况下为txtfirst.style)都是text string,而不是number。像"50px" < "300px"这样的测试不会比较50是否小于300,而是比较文本值lexicographically

如果您实际上想比较像素数量,则可以使用parseInt函数将50px之类的值转换为数字50。然后您的测试将如下所示:

parseInt(txtfirst.style.top) < 300


现在,由于您对建议感兴趣,因此以下是解决该问题和建议解决方案的方法中的许多问题。

使用内联样式通常存在问题(主观)


内联样式在CSS中具有最高优先级,这在用户拥有自己的样式表的情况下可能会出现问题,因为其中设置的属性将被忽略,而有利于内联设置的属性。
假定将是实际使用的值,则读取内联样式的属性完全是错误的。内联样式对象跟踪分配的值,而不是计算或使用的值。另一方面,Window::getComputedStyle(element)函数检索元素的计算样式。


解?使用getComputedStyle读取属性并将它们直接写入首选的样式表(如果需要,可以为空)(document.styleSheets,反映所有link rel=stylesheetstyle元素):

function rule(selector) {
    var sheet = document.styleSheets[0];
    return Array.prototype.find.call(sheet.cssRules, rule => rule.selectorText == selector);
}
var txtfirst = document.getElementById("txtfirst");
window.onscroll = function() {    
    var ypos = window.pageYOffset;
    var style = rule(".text-first").style;
    style.top = ypos * 0.4 + "px";
    if(parseInt(getComputedStyle(txtfirst).top) > 300) {
        style.top = "0px";
    }
}


上面的rule函数从找到的第一个样式表(您只有一个)中返回带有匹配选择器(例如.text-firsthtml, body)的CSS规则(其中包含一组CSS属性)。规则的style属性是指包含规则中设置的所有CSS属性的对象。它的行为与内联样式对象相同。请注意,您在上面的任何地方都没有使用内联样式,而是写入了样式表对象(由文档的<style>...</style>片段初始化)并回读了计算所得的值。

解决将scroll事件用于动画的问题

首先,您是否知道旧版本的iOS在滚动时不会触发scroll事件?这将使您的视差效果停滞不前,因为在用户停止滚动后会触发单个scroll事件。这与浏览器进行页面滚动的方式有关–使用受限制的移动CPU资源来实现平滑的页面滚动动画,仅每秒一次执行scroll事件处理程序的JavaScript代码60次,这被认为过于慷慨,而Apple取而代之的是颇有争议的解决方案,因为它们原本就是好的UX。

无论如何,如果不使用scroll事件该怎么办?您可以使用旧的setInterval

function rule(selector) {
    var sheet = document.styleSheets[0];
    return Array.prototype.find.call(sheet.cssRules, rule => rule.selectorText == selector);
}
var txtfirst = document.getElementById("txtfirst");
var old_window_pageYOffset = window.pageYOffset;
setTimeout(function() {    
    var ypos = window.pageYOffset;
    if(ypos != old_window_pageYOffset) return;
    old_window_pageYOffset = ypos;
    var style = rule(".text-first").style;
    style.top = ypos * 0.4 + "px";
    if(parseInt(getComputedStyle(txtfirst).top) > 300) {
        style.top = "0px";
    }
}, 1000 / 60);


上面所做的是确保在整个页面的生命周期中每秒调用一次函数60次,但是会在每次调用时检查窗口的滚动位置自上次调用以来是否发生了更改,仅在有旧代码的情况下才调用旧代码,不做任何其他事情。显然,这根本不使用scroll事件。综上所述,较新的iOS版本已恢复了行为,并且滚动位置的每次更改都会触发scroll事件。意味着您可能只是想将其用作基准并取决于事件而不是setInterval。后者的一个免费好处是您可以控制视差效果的运行速度。

我还建议您使用requestAnimationFrame,它比setInterval更“智能”,因为如果用户代理认为不需要动画,例如,如果整个页面选项卡不可见或与之交互,则用户代理将不会调用您的代码。目前的用户。请放心,动画将在“需要时”运行:

function rule(selector) {
    var sheet = document.styleSheets[0];
    return Array.prototype.find.call(sheet.cssRules, rule => rule.selectorText == selector);
}
var txtfirst = document.getElementById("txtfirst");
var old_window_pageYOffset = window.pageYOffset;
requestAnimationFrame(function() {    
    var ypos = window.pageYOffset;
    if(ypos != old_window_pageYOffset) return;
    old_window_pageYOffset = ypos;
    var style = rule(".text-first").style;
    style.top = ypos * 0.4 + "px";
    if(parseInt(getComputedStyle(txtfirst).top) > 300) {
        style.top = "0px";
    }
});


上面的代码可以很好地尝试视差效果,除了那些与视差效果无关的较小的nitpicks之外:


当我们有on*name*时,我不使用addEventListener系列功能。前者是每个处理程序的一个属性,并且不能保证您的脚本是这些属性的唯一使用者-它们可能已经由浏览器扩展设置。我们可以争辩说网页作者是否拥有专有权并可以访问他们可以使用的所有属性,但是至少我已经解释了我的理由。使用addEventListener("scroll", function() { ... })并没有明显的缺点。
您无需同时使用类名和ID来引用元素。 document.querySelector(".text-field")将返回其类名称列表中第一个具有“文本字段”的可用元素。


我已经保存了最后的最好方法-Pure CSS Parallax Websites依靠CSS perspective属性以及其他一些方法来实现(尽管对于浏览器而言,没有一些小漏洞,但没有任何JavaScript)所需的效果。它还提到了我上面警告过的一些相同的事情,这些都是我试图规避和解释的事情。

如果您不想阅读(并理解)文档,建议您使用一个方便的抽象方法-插件,框架,库或为此目的的某些东西,这将使您不必费解繁琐的操作。现代CSS和兼容的浏览器模型非常复杂,足以使这些解决方案得以存在和发展。

关于javascript - 视差-元素毛刺,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50890728/

相关文章:

css - 左浮动的 div 位于另一个 div 下方

javascript - Facebook 的 BigPipe 和 SEO : Cloaking?

javascript - 如何使用 JavaScript 查看已打开的广播 channel ?

javascript - xmlhttprequest 超时/中止未按预期工作?

html - 由于 html 代码的微小变化,php 链接丢失

html - Bootstrap4控制inline-form的宽度

javascript - 正则表达式按引号和加号拆分

html - 如何在 AngularJS 中使用图像作为背景?

html - <figure> 中高度和宽度的响应图像

javascript - 创建像谷歌图片页面这样的框架