CSS3-动画元素如果在视口中可见(页面滚动)
Posted
技术标签:
【中文标题】CSS3-动画元素如果在视口中可见(页面滚动)【英文标题】:CSS3-Animate elements if visible in viewport (Page Scroll) 【发布时间】:2015-02-12 06:22:48 【问题描述】:我已经在我的 html 页面上的各种 div 元素中添加了 CSS 动画。但是所有的动画同时播放并且我在页面底部看不到动画。我怎样才能让它们在我滚动时播放在页面下方?
【问题讨论】:
使用 JS,如果元素在 在视口中,则为所有元素添加一个类。该类应该触发 CSS3 动画。 【参考方案1】:使用 IntersectionObserver API
IntersectionObserver API 提供了一种异步观察目标元素与祖先元素或***文档视口的交集变化的方法。
这是一个当元素在视口中时触发classList toggle 的示例:
const inViewport = (entries, observer) =>
entries.forEach(entry =>
entry.target.classList.toggle("is-inViewport", entry.isIntersecting);
);
;
const Obs = new IntersectionObserver(inViewport);
const obsOptions = ; //See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options
// Attach observer to every [data-inviewport] element:
const ELs_inViewport = document.querySelectorAll('[data-inviewport]');
ELs_inViewport.forEach(EL =>
Obs.observe(EL, obsOptions);
);
[data-inviewport] /* THIS DEMO ONLY */
width:100px; height:100px; background:#0bf; margin: 150vh 0;
/* inViewport */
[data-inviewport="scale-in"]
transition: 2s;
transform: scale(0.1);
[data-inviewport="scale-in"].is-inViewport
transform: scale(1);
[data-inviewport="fade-rotate"]
transition: 2s;
opacity: 0;
[data-inviewport="fade-rotate"].is-inViewport
transform: rotate(180deg);
opacity: 1;
Scroll down...
<div data-inviewport="scale-in"></div>
<div data-inviewport="fade-rotate"></div>
观察者选项
要定义另一个父引用元素,请使用可观察选项对象内的root
选项。您还可以选择rootMargin
和超级有用的threshold
选项
const obsOptions =
// Default is null (Browser viewport). Set a specific parent element:
root: document.querySelector('#someSpecificParent'),
// add 40px inner "margin" area at which the observer starts to calculate:
rootMargin: '40px',
// Default is 0.0 meaning the callback is called as soon 1 pixel is inside the viewport.
// Set to 1.0 to trigger a callback when 100% of the target element is inside the viewport,
// or i.e: 0.5 when half of the target element is visible:
threshold: 0.5,
;
查看另一个interesting use case that uses the IntersectionObserver API's threshold
选项。
补充阅读:
w3.org developer.mozilla.org caniuse.com使用 native IntersectionObserver API 是解决此问题的最高效的方法。 如果您想了解我们过去是如何解决类似需求的,请以 this answer with a small custom plugin 为例。
【讨论】:
是的,我包含了插件 @Ajith 您的目标是类为$(".box")
的元素,但在您的 HTML 中您没有定义此类。我已经添加了这些类,但到目前为止还没有动画......没有时间去处理你的整个代码......再次查看我的示例并从那里开始。试着找出问题所在。我认为这是一些定位问题......但我不确定。
@RokoC.Buljan 你知道如何删除这个类,这样当你往回滚动时它会再次触发动画?
@probablybest 只需使用$(this).toggleClass("triggeredCSS3", !!px );
jsfiddle.net/RokoCB/tw6g2oeu/16
在某些网络浏览器上$(window).height()
返回文档高度而不是视口高度,除非您添加严格的文档类型,如here 所述。也许这对某人有帮助,因为我花了一些时间才弄清楚。【参考方案2】:
仍然是 javascript,但在这个版本中,您不需要监听滚动事件。 速度和性能比每次检查对象是否在视口中要好得多。
检查这个: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
使用Intersection Observer,您可以在元素可见时定义回调。
选项:root
: null threshold
: 0.3
function callbackFunc(entries, observer)
entries.forEach(entry =>
var txt = entry.target.id + " visibility: " + entry.isIntersecting;
document.getElementById('log').appendChild(document.createTextNode(txt));
document.getElementById('log').appendChild(document.createElement("br"));
);
let options =
root: null,
rootMargin: '0px',
threshold: 0.3
;
let observer = new IntersectionObserver(callbackFunc, options);
observer.observe(document.getElementById('firstBlock'));
observer.observe(document.getElementById('secondBlock'));
#firstBlock
width: 50vw;
height: 80vh;
background: red;
#secondBlock
width: 50vw;
height: 80vh;
background: blue;
#log
width: 200px;
height: 80vh;
position: fixed;
right: 0px;
top: 10px;
overflow: auto;
First Block:
<div id='firstBlock'> </div>
<br><br><br>
Second Block:
<div id='secondBlock'> </div>
<div id='log'>Log: </div>
【讨论】:
我觉得现在应该接受这个答案。较旧的示例仍然有效,但已经过时了。 这应该是正确的答案并展示了良好的做法,避免了数千次执行功能。 当您滚动回第一个块时,删除第二个块可见性文本怎么样?看起来应该不会太难…… 看起来它还不是 100% 精确,即使我看到第一个块的某些部分,第一个块的可见性也会变成错误【参考方案3】:另一种方法是使用滚动事件监听器
document.addEventListener("DOMContentLoaded", function(event)
document.addEventListener("scroll", function(event)
const animatedBoxes = document.getElementsByClassName("animated-box");
const windowOffsetTop = window.innerHeight + window.scrollY;
Array.prototype.forEach.call(animatedBoxes, (animatedBox) =>
const animatedBoxOffsetTop = animatedBox.offsetTop;
if (windowOffsetTop >= animatedBoxOffsetTop)
addClass(animatedBox, "fade-in");
);
);
);
function addClass(element, className)
const arrayClasses = element.className.split(" ");
if (arrayClasses.indexOf(className) === -1)
element.className += " " + className;
.animated-box
width: 150px;
height: 150px;
margin-top: 100vh;
background: blue;
.fade-in
-webkit-animation: fade-in 1.2s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
animation: fade-in 1.2s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
@-webkit-keyframes fade-in
0%
-webkit-transform: translateY(50px);
transform: translateY(50px);
opacity: 0;
100%
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
@keyframes fade-in
0%
-webkit-transform: translateY(50px);
transform: translateY(50px);
opacity: 0;
100%
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
<div>
Start scrolling down...
<div class="animated-box">
</div>
<div class="animated-box">
</div>
<div class="animated-box">
</div>
<div class="animated-box">
</div>
<div class="animated-box">
</div>
</div>
【讨论】:
以上是关于CSS3-动画元素如果在视口中可见(页面滚动)的主要内容,如果未能解决你的问题,请参考以下文章