最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why does threshold on IntersectionObserver not work on my element? - Stack Overflow

programmeradmin11浏览0评论

IntersectionObserver does not work as intended on my element in React. As you can see in code I have threshold set to 0.5 but animations are fired as soon as they appear on the screen and I do not understand why. Can someone explain? (I've included CSS just in case that has something to do with it because I'm not sure.)

Demo video

import { buttonHoverAnimation, rotateAnimation } from "../../animations/animations";
import backgroundImage from "../../assets/images/pexels.jpg";
import smileIcon from "../../assets/icons/smile.svg";
import "./ExploreCard.css";
import { useEffect, useRef } from "react";
import { slideAnimation } from "../../animations/animations";
type ExploreCardProps = {
  reverse?: boolean;
};

function ExploreCard({ reverse }: ExploreCardProps) {

  const buttonHover = buttonHoverAnimation({}, {}, 30);
  const contentRef = useRef<HTMLDivElement>(null);
  const imageRef = useRef<HTMLDivElement>(null)
  // Handler Slide animation
  useEffect(() => {
    if (!contentRef.current) return;
    const animation = slideAnimation(
      contentRef.current,
      reverse ?
      [-1000, 0] : [1000, 0]
    );
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        animation.play();
        observer.unobserve(entries[0].target);
      }
    }, { threshold: 0.5 });
    observer.observe(contentRef.current);
    return () => {
      observer.disconnect();
    };
  });
  // Handle rotate animation ,
  useEffect(() => {
    if (!imageRef.current) return;
    const animation = rotateAnimation(imageRef.current)
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        animation.play();
        observer.unobserve(entries[0].target);
      }
    },
     { threshold: 0.5 }
    );
    observer.observe(imageRef.current);
    return () => {
      observer.disconnect();
    };
  }, []);


  return (
    <div className={`explore-card ${reverse ? "reverse" : ""}`}>
      <div className="explore-image-wrapper" ref={imageRef}>
        <img src={backgroundImage} alt="Background-image" />
      </div>
      <div className={`explore-card-popup ${reverse ? "reverse" : ""}`}>
        <h2>2X</h2>
        <p>Faster</p>
      </div>
      <div className={`explore-content-wrapper ${reverse ? "reverse" : ""}`}ref={contentRef}>
        <div className="explore-content-icon">
          <img src={smileIcon} alt=":)" />
          <p>QUICK</p>
        </div>
        <div className="explore-content-header">
          <h1 className="explore-content-header-bold">HOME</h1>
          <h1 className="explore-content-header-italic">Refresh</h1>
        </div>
        <div className="explore-content-description">
          Experience the ultimate expert support — Creating spaces where comfort
          and productivity thrive.
        </div>
        <div className="explore-content-button">
          <button
            onMouseOver={buttonHover.handleMouseIn}
            onMouseOut={buttonHover.handleMouseOut}
          >
            <span>EXPLORE</span>
            <span>EXPLORE</span>
          </button>
        </div>
      </div>
    </div>
  );
}

export default ExploreCard;
@font-face {
  font-family: intern-light;
  src: url('../../assets/fonts/static/Inter_18pt-Thin.ttf');
}

@font-face {
  font-family: intern-regular;
  src: url('../../assets/fonts/static/Inter_18pt-Light.ttf');
}

@font-face {
  font-family: intern-bold;
  src: url('../../assets/fonts/static/Inter_24pt-Black.ttf');
}

@font-face {
  font-family: intern-italic;
  src: url('../../assets/fonts/static/Inter_18pt-ThinItalic.ttf');
}

.explore-card {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  position: relative;
  gap: 2vw;
  margin-top: 15vh;
  overflow: hidden;
  height: 50vh;
}

.explore-content-wrapper {
  width: 35%;
  display: flex;
  padding: 7%;
  display: inline-block;
}

.explore-content-icon > p{
  font-family: intern-regular;
  margin-left: 10px;
  font-weight: 500;
  letter-spacing: 2px;
}

.explore-content-icon {
  display: flex;
}

.explore-content-icon > img {
  width: 30px;
}

.explore-image-wrapper {
  display: flex;
  height: 50vh;
  width: 25%;
  border-radius: 70px;
  overflow: hidden;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 2;
}

.explore-image-wrapper > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.explore-card-popup {
  top: 10%;
  left: 30%;
  border-radius: 50px;
  position: absolute;
  height: 34%;
  width: 13%;
  background-color: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(10px);
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  -webkit-box-shadow: 0px 10px 50px -10px rgba(0, 0, 0, 0.75);
  -moz-box-shadow: 0px 10px 50px -10px rgba(0, 0, 0, 0.75);
  box-shadow: 0px 10px 50px -10px rgba(0, 0, 0, 0.75);
  z-index: 3;
}

.explore-card-popup > h2 {
  font-family: intern-regular;
  font-weight: 100;
  font-size: 30px;
  margin: 0;
}

.explore-card-popup > p {
  font-family: intern-light;
  font-size: 20px;
  font-weight: 600;
  margin-top: 0;
  letter-spacing: 2px;
}

.explore-content-header {
  display: flex;
  font-size: 60px;
}

.explore-content-header > h1 {
  margin-top: 5px;
  margin-right: 10%;
  margin-bottom: 5px;
}

.explore-content-header-bold {
  font-family: intern-regular;
  font-weight: 300;
}

.explore-content-header-italic {
  font-family: intern-italic;
  font-weight: 100;
}

.explore-content-description {
  font-family: intern-regular;
  font-size: 18px;
  letter-spacing: 2px;
  line-height: 30px;
  margin-bottom: 30px;
}

.explore-content-button > button {
  font-family: intern-regular;
  height: 1.3rem;
  font-size: 1.3rem;
  background: none;
  border: 0;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.explore-content-button > button > span {
  position: relative;
  transition: transform 0.7s, opacity 0.7s;
  margin: 0;
}

.explore-card.reverse {
  flex-direction: row-reverse;
}
.explore-card-popup.reverse {
  left: 57%;
}

IntersectionObserver does not work as intended on my element in React. As you can see in code I have threshold set to 0.5 but animations are fired as soon as they appear on the screen and I do not understand why. Can someone explain? (I've included CSS just in case that has something to do with it because I'm not sure.)

Demo video

import { buttonHoverAnimation, rotateAnimation } from "../../animations/animations";
import backgroundImage from "../../assets/images/pexels.jpg";
import smileIcon from "../../assets/icons/smile.svg";
import "./ExploreCard.css";
import { useEffect, useRef } from "react";
import { slideAnimation } from "../../animations/animations";
type ExploreCardProps = {
  reverse?: boolean;
};

function ExploreCard({ reverse }: ExploreCardProps) {

  const buttonHover = buttonHoverAnimation({}, {}, 30);
  const contentRef = useRef<HTMLDivElement>(null);
  const imageRef = useRef<HTMLDivElement>(null)
  // Handler Slide animation
  useEffect(() => {
    if (!contentRef.current) return;
    const animation = slideAnimation(
      contentRef.current,
      reverse ?
      [-1000, 0] : [1000, 0]
    );
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        animation.play();
        observer.unobserve(entries[0].target);
      }
    }, { threshold: 0.5 });
    observer.observe(contentRef.current);
    return () => {
      observer.disconnect();
    };
  });
  // Handle rotate animation ,
  useEffect(() => {
    if (!imageRef.current) return;
    const animation = rotateAnimation(imageRef.current)
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        animation.play();
        observer.unobserve(entries[0].target);
      }
    },
     { threshold: 0.5 }
    );
    observer.observe(imageRef.current);
    return () => {
      observer.disconnect();
    };
  }, []);


  return (
    <div className={`explore-card ${reverse ? "reverse" : ""}`}>
      <div className="explore-image-wrapper" ref={imageRef}>
        <img src={backgroundImage} alt="Background-image" />
      </div>
      <div className={`explore-card-popup ${reverse ? "reverse" : ""}`}>
        <h2>2X</h2>
        <p>Faster</p>
      </div>
      <div className={`explore-content-wrapper ${reverse ? "reverse" : ""}`}ref={contentRef}>
        <div className="explore-content-icon">
          <img src={smileIcon} alt=":)" />
          <p>QUICK</p>
        </div>
        <div className="explore-content-header">
          <h1 className="explore-content-header-bold">HOME</h1>
          <h1 className="explore-content-header-italic">Refresh</h1>
        </div>
        <div className="explore-content-description">
          Experience the ultimate expert support — Creating spaces where comfort
          and productivity thrive.
        </div>
        <div className="explore-content-button">
          <button
            onMouseOver={buttonHover.handleMouseIn}
            onMouseOut={buttonHover.handleMouseOut}
          >
            <span>EXPLORE</span>
            <span>EXPLORE</span>
          </button>
        </div>
      </div>
    </div>
  );
}

export default ExploreCard;
@font-face {
  font-family: intern-light;
  src: url('../../assets/fonts/static/Inter_18pt-Thin.ttf');
}

@font-face {
  font-family: intern-regular;
  src: url('../../assets/fonts/static/Inter_18pt-Light.ttf');
}

@font-face {
  font-family: intern-bold;
  src: url('../../assets/fonts/static/Inter_24pt-Black.ttf');
}

@font-face {
  font-family: intern-italic;
  src: url('../../assets/fonts/static/Inter_18pt-ThinItalic.ttf');
}

.explore-card {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  position: relative;
  gap: 2vw;
  margin-top: 15vh;
  overflow: hidden;
  height: 50vh;
}

.explore-content-wrapper {
  width: 35%;
  display: flex;
  padding: 7%;
  display: inline-block;
}

.explore-content-icon > p{
  font-family: intern-regular;
  margin-left: 10px;
  font-weight: 500;
  letter-spacing: 2px;
}

.explore-content-icon {
  display: flex;
}

.explore-content-icon > img {
  width: 30px;
}

.explore-image-wrapper {
  display: flex;
  height: 50vh;
  width: 25%;
  border-radius: 70px;
  overflow: hidden;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 2;
}

.explore-image-wrapper > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.explore-card-popup {
  top: 10%;
  left: 30%;
  border-radius: 50px;
  position: absolute;
  height: 34%;
  width: 13%;
  background-color: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(10px);
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  -webkit-box-shadow: 0px 10px 50px -10px rgba(0, 0, 0, 0.75);
  -moz-box-shadow: 0px 10px 50px -10px rgba(0, 0, 0, 0.75);
  box-shadow: 0px 10px 50px -10px rgba(0, 0, 0, 0.75);
  z-index: 3;
}

.explore-card-popup > h2 {
  font-family: intern-regular;
  font-weight: 100;
  font-size: 30px;
  margin: 0;
}

.explore-card-popup > p {
  font-family: intern-light;
  font-size: 20px;
  font-weight: 600;
  margin-top: 0;
  letter-spacing: 2px;
}

.explore-content-header {
  display: flex;
  font-size: 60px;
}

.explore-content-header > h1 {
  margin-top: 5px;
  margin-right: 10%;
  margin-bottom: 5px;
}

.explore-content-header-bold {
  font-family: intern-regular;
  font-weight: 300;
}

.explore-content-header-italic {
  font-family: intern-italic;
  font-weight: 100;
}

.explore-content-description {
  font-family: intern-regular;
  font-size: 18px;
  letter-spacing: 2px;
  line-height: 30px;
  margin-bottom: 30px;
}

.explore-content-button > button {
  font-family: intern-regular;
  height: 1.3rem;
  font-size: 1.3rem;
  background: none;
  border: 0;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.explore-content-button > button > span {
  position: relative;
  transition: transform 0.7s, opacity 0.7s;
  margin: 0;
}

.explore-card.reverse {
  flex-direction: row-reverse;
}
.explore-card-popup.reverse {
  left: 57%;
}

Share Improve this question edited Mar 27 at 13:26 isherwood 61.2k16 gold badges121 silver badges170 bronze badges asked Mar 27 at 13:23 Zura GabichvadzeZura Gabichvadze 666 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 0

After 2 days of searching, I didn't find any solution so, I just use react-hook-observer and threshold works as intended, I do not know whether or not it's react thing that threshold doesn't work but I couldn't find any answers online. So for now I am happy to share that everything works much better.

发布评论

评论列表(0)

  1. 暂无评论