视差 - 元素故障



所以我一直在尝试围绕这个叫做视差的整洁效果。基本上背景滚动速度比前景元素慢。

我发现了这个有效的新"技巧"。随着滚动的进行,更改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在您的情况下)是一个文本字符串,而不是一个数字。像"50px" < "300px"这样的测试不会比较 50 是否小于 300,而是按字典顺序比较文本值。

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

修复了将scroll事件用于动画的问题

首先,您是否知道旧版本的iOS在您滚动时不会触发scroll事件?这将阻止视差效果在其轨道上消失,因为在用户停止滚动将触发单个scroll事件。这与浏览器进行页面滚动的方式有关 - 为了使用受限的移动CPU资源实现平滑的页面滚动动画,每秒运行60次由scroll事件处理程序提供的JavaScript代码被认为是一个过于慷慨的提议,苹果转而选择了有争议的解决方案,因为他们被良好的用户体验所占据。

无论如何,如果不使用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";
}
});

上面的代码是对视差效果的一次不错的尝试,除了一些与视差效应无关的小吹毛求疵:

  • 当我们有addEventListener时,我不使用on*name*系列函数。前者是每个处理程序的一个属性,并且不能保证您的脚本是这些属性的唯一使用者 - 它们可能已经由浏览器扩展设置。我们可以争论网页作者是否拥有独家所有权和访问他们可以获得的所有财产,但至少我已经解释了我的理由。我知道使用addEventListener("scroll", function() { ... })没有明显的缺点。

  • 元素不需要同时使用类名和ID 来引用它。document.querySelector(".text-field")将返回在其类名列表中具有"text-field"的第一个可用元素。

我已经把最好的留到了最后 - 纯CSS视差网站通过实现(尽管并非没有一些针对有错误的浏览器的小技巧)所需的效果,根本没有任何JavaScript,依靠CSSperspective属性和其他一些。它还提到了我上面警告过的一些同样的事情,我试图规避和解释的事情。

如果你不想阅读(和理解)文档,我建议你求助于一个方便的抽象 - 一个插件,一个框架,一个库或为此目的的东西,这将使你不必去摸索这个的复杂性。现代CSS和兼容的浏览器模型足够复杂,这些解决方案的存在和发展。

最新更新