CSS3-Animate 元素(如果在视口中可见)(页面滚动)

IT技术 javascript jquery html css animation
2021-03-07 13:39:34

我已将 CSS 动画添加到我的 html 页面上的各种 div 元素。但是所有动画同时播放且我看不到页面底部的动画。如何在向下滚动页面时让它们播放?

3个回答

使用 IntersectionObserver API

所述IntersectionObserver API提供了一种异步观察目标元素的交点的变化与一个祖先元素或具有顶级文档的视口。

这是一个当 Element 在视口中时触发classList 切换的示例

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>

观察者选项

要定义另一个父引用元素,请使用rootObservable 选项对象中的选项。根据您的喜好,还有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, 
};

查看另一个使用 IntersectionObserver APIthreshold选项的有趣用例

补充阅读:


使用本IntersectionObserver API 是解决此问题高效方法。
如果您想了解我们过去如何解决类似需求,请以一个小型自定义插件为例查看此答案

@probablybest 只需使用$(this).toggleClass("triggeredCSS3", !!px ); jsfiddle.net/RokoCB/tw6g2oeu/16
2021-05-02 13:39:34
@Ajith 你使用 class 定位元素,$(".box")但在你的 HTML 中你没有定义这样的 class。我已经添加了这些类,但到目前为止还没有动画......没有时间遍历你的整个代码......再次查看我的示例并从那里开始。试着找出问题所在。我认为它的定位问题......但我不确定。
2021-05-04 13:39:34
是的,我包含了插件
2021-05-12 13:39:34
在一些网络浏览器$(window).height(),除非你添加一个严格的doctype声明为返回文档,而不是高度的视口的高度位置也许这对某人有帮助,因为我花了一些时间才弄明白。
2021-05-13 13:39:34
@RokoC.Buljan 您知道如何删除该类,以便在向后滚动时它会再次触发动画吗?
2021-05-16 13:39:34

仍然是 Javascript,但在这个版本中你不需要监听滚动事件。速度和性能比每次检查对象是否在视口中要好得多。

检查这个:https : //developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

使用Intersection Observer,您可以在元素可见时定义回调。

选项:
root: null << 如果您希望它在您的视口(可见区域)内,请设置为 null
threshold: 0.3 << 表示 30% 的可见性。如果设置为 0.3,则在可见度达到至少 30% 时调用一次回调,并且在可见度低于 30% 时调用一次回调。

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% 精确,即使我看到第一个块的某些部分,第一个块的可见性也会变为假
2021-04-22 13:39:34
我觉得现在应该接受这个答案。较旧的示例仍然有效,但已经过时了。
2021-05-05 13:39:34
当您滚动回第一个块时删除第二个块可见性文本怎么样?好像应该不会太难...
2021-05-09 13:39:34
这应该是正确的答案并展示了良好的实践,避免了数千次执行函数。
2021-05-10 13:39:34

另一种方法是使用滚动事件侦听器

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>