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

javascript - Jumps and lags when switching between sections (GSAP ScrollTrigger) - Stack Overflow

programmeradmin5浏览0评论

I am new to frontend and have started using gsap for animations. I use gsap mainly for switching between sections. On screens larger than 576px I have a problem: when switching between sections there are jumps and they disappear after a while if you scroll up and down the page. Maybe someone has encountered this ? I don't seem to have a lot of animations so far, but already so laggy.

Here's what I tried to do:

  1. Remove all possible negative margins.

  2. Add to all elements to which the transition is made, properties:

    transform: translate3d(0,0,0,); will-change: transform; backface-visibility: hidden;

  3. Set property ease - sine, power1, power2.

  4. 've noticed that by removing the lags and jumps on large screens disappear. On normal laptops everything is displayed normally.

  5. As soon as I return the element, everything starts lagging again. The resolution of the image used is 2560 x 3072 pixels and the size is 272kb. The sizes of the other images for the background are: 2560 x 3658 and 2560 x 1534 pixels. All of them are set via css as backgroud.

  6. I've already resized all the large images for the background and it still lags and jumps when scrolling.

All this had no effect.

In the mobile version I have a lot of animation that works perfectly with gsap.

I tried to recreate a minimal demonstration of the project. The jumps and lags when switching to different sections remain.

/* FORM HANDLER */

// Disable automatic scroll recovery
window.history.scrollRestoration = "manual";
// Force a scroll to the beginning of the page
window.scrollTo(0, 0);

// PARALLAX
document.addEventListener("DOMContentLoaded", () => {
  const welcome = document.querySelector(".welcome");
  const block_desc = document.querySelector(".block-desc");

  const zones = document.querySelector(".zones");
  const pool = document.querySelector(".zones .pool-spa");
  const fitness = document.querySelector(".zones .fitness-roof");

  gsap.registerPlugin(ScrollTrigger, ScrollToPlugin);

  let currentIndex = 0; // Current section index
  let isScrolling = false; // Flag to prevent multiple scrolls
  let footerReachedTopOnce = false; // Flag that is turned on after the top of the footer is reached for the first time

  const window_width = window.innerWidth;
  // ENABLE ONLY ON MOBILE
  if (window_width < 576) {
  } else {
    // ENABLE ON DEVICE WITH WINDOW WIDTH >= 576px

    // List of sections tables to be switched
    const sections_tb = gsap.utils.toArray([
      ".welcome",
      ".zones .pool-spa",
      ".zones .fitness-roof",
      ".block-img-bottom",
    ]);

    // List of sections PC to be switched
    const sections_pc = gsap.utils.toArray([
      ".welcome",
      ".block-desc",
      ".zones .pool-spa",
      ".zones .fitness-roof",
      ".block-img-bottom",
    ]);

    /* TABLET <1200px */
    if (window_width < 1200) {
      const duration_main = 1.8; // Duration of animation of transitions between sections

      /* Parallax for bg of zones */
      gsap.to(".zones .zones-bg", {
        y: "80%", // Параллакс-эффект
        ease: "power1.inOut",
        scrollTrigger: {
          trigger: ".zones",
          start: "top top",
          end: "bottom bottom",
          scrub: true,
        },
      });

      function scrollToSectionTB(index) {
        if (isScrolling || index < 0 || index >= sections_tb.length) return;

        isScrolling = true;
        let targetSection = sections_tb[index];
        let offset = 60; // По умолчанию смещение составляет 60px от верха секции

        // set offset for different section or execution prevent action before change section
        switch (index) {
          case 1: //
            break;
          case 3: //
            break;
          case 7: //
            break;
        }

        // change section
        gsap.to(window, {
          duration: duration_main,
          scrollTo: { y: targetSection, offsetY: offset},
          ease: "power1.inOut",
          onStart: () => updateClassesTB(index),
          onComplete: () => {
            isScrolling = false;
            currentIndex = index;
          },
        });
      }

      function updateClassesTB(index) {
        // Display logo of head on all sections_tb but not on welcome
      }

      // Page reloading fix with saving last section
      window.history.scrollRestoration = "manual";
      window.addEventListener("load", () => {
        let savedIndex = sessionStorage.getItem("currentSection") || 0;

        setTimeout(() => {
          ScrollTrigger.refresh();
          scrollToSectionTB(parseInt(savedIndex, 10));
        }, 500);
      });

      window.addEventListener("beforeunload", () => {
        sessionStorage.setItem("currentSection", currentIndex);
      });

      /* ONLY PC >=1200px*/
    } else {
      /* Parallax for bg of zones */
      gsap.to(".zones .zones-bg", {
        y: "50vw", // Параллакс-эффект
        ease: "none",
        scrollTrigger: {
          trigger: ".zones",
          start: "top top",
          end: "bottom bottom",
          scrub: true,
        },
      });

      function scrollToSectionPC(index) {
        if (isScrolling || index < 0 || index >= sections_pc.length) return;

        let duration_main = 1.8; // Duration of animation of transitions between sections

        if (
          (currentIndex === 1 && index === 0) ||
          (currentIndex === 0 && index === 1)
        ) {
          duration_main = 2.2;
        }

        isScrolling = true;
        let targetSection = sections_pc[index];
        let offset = 0; // По умолчанию смещение составляет 30px от верха секции

        const height_section = sections_pc[index].offsetHeight / 2;
        let offset_center = window.innerHeight / 2 - height_section;
        
        offset = offset_center;

        // change section
        gsap.to(window, {
          duration: duration_main,
          scrollTo: { y: targetSection, offsetY: offset},
          ease: "power1.inOut",
          onStart: () => updateClassesPC(index),
          onComplete: () => {
            isScrolling = false;
            currentIndex = index;
          },
        });
      }

      function updateClassesPC(index) {
        switch (index) {
          case 0: // welcome
            welcome.classList.remove("animate");
            break;
          case 1: // .block-desc
            welcome.classList.add("animate");
            break;
          case 2: // 
            welcome.classList.add("animate");
            break;
        }
      }

      // Page reloading fix with saving last section
      window.history.scrollRestoration = "manual";
      window.addEventListener("load", () => {
        let savedIndex = sessionStorage.getItem("currentSection") || 0;

        setTimeout(() => {
          ScrollTrigger.refresh();
          scrollToSectionPC(parseInt(savedIndex, 10));
        }, 500);
      });

      window.addEventListener("beforeunload", () => {
        sessionStorage.setItem("currentSection", currentIndex);
      });
    }

    let touchStart = 0;
    let scrollToSection =
      window_width < 1200 ? scrollToSectionTB : scrollToSectionPC;

    const sections = window_width < 1200 ? sections_tb : sections_pc;

    /* HANDLE SCROLL ON TABLET AND PC */
    function handleScrollTabletPC(event) {
      if (isScrolling) {
        return;
      }

      let scrollAmount = event.deltaY || event.touches?.[0]?.clientY; // Define input type
      if (Math.abs(scrollAmount) < 20) return; // Filter out movements that are too small

      if (scrollAmount > 0 && currentIndex < sections.length - 1) {
        // scroll down
        scrollToSection(currentIndex + 1);
      } else if (scrollAmount < 0 && currentIndex > 0) {
        // scroll up
        scrollToSection(currentIndex - 1);
      }
    }

    /* GLOBAL SCROLL FOR ALL SECTIONS FOR TABLET AND PC*/
    /* Handler scroll on PC */
    if (window_width >= 1200) {
      window.addEventListener("wheel", handleScrollTabletPC, {
        passive: false,
      });
    }

    /* Handler scroll and swipe on tablet */
    if (window_width < 1200) {
      window.addEventListener("wheel", handleScrollTabletPC, {
        passive: false,
      });

      window.addEventListener("touchstart", (e) => {
        touchStart = e.touches[0].clientY;
      });

      window.addEventListener("touchmove", (e) => {
        let touchEnd = e.touches[0].clientY;
        let delta = touchStart - touchEnd;
        handleScrollTabletPC({
          deltaY: delta,
          touches: e.touches,
          preventDefault: () => e.preventDefault(),
        });
      });
    }
  }
});
/* RESET */

/* 2. Remove default margin */
* {
  margin: 0;
}

body {
  font-family: "Geologica", serif;
  color: white;
  font-optical-sizing: auto;
  font-weight: 400;
  font-style: normal;
  font-size: 16px;
  background-color: #000000;
  overflow: hidden;
  height: 100%;
}

main {
  overflow: hidden;
}

.container {
  padding: 0 4rem 0 2.125rem;
}

.section-top {
  position: relative;
  z-index: 1;
}

@media screen and (min-width: 1200px) {
  .section-top {
    padding-bottom: 10rem;
  }
}

/* welcome */
.welcome {
  position: relative;
  height: calc(100vw* 2.38);
  width: auto;
  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 80%, rgba(0, 0, 0, 0.9) 100%), url(".webp?rlkey=7f8r2t5cdqhcxw0a0eji9z862&st=ema78f0y&raw=1");
  background-repeat: no-repeat;
  background-origin: content-box;
  background-size: 105%;
  z-index: 2;
}

@media screen and (min-width: 576px) {
  .welcome {
    height: calc(100vw* 1.43);
    background-image: url(".webp?rlkey=nvvhv52h9fx9h4m2e7epra1q3&st=pn7vfzw3&raw=1");
  }
}


@media screen and (min-width: 576px) {

  .welcome {
    transition: transform 1s linear 0.2s;
    will-change: transform;
  }

  .welcome.animate {
    transform: scale(108%);
  }

/* block-desc */
.block-desc {
  font-size: 1.063rem;
  font-weight: 100;
  line-height: 28px;
  padding-bottom: .98rem;
  position: relative;
  z-index: 3;
}

@media screen and (min-width: 576px) {
  .block-desc {
    font-weight: 100;
    font-size: .9rem;
    line-height: 26px;
    display: flex;
    justify-content: center;
    margin-top: -50vh;
    background-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0) 100%);
    background-size: cover;
    will-change: transform;
    z-index: 3;
  }

  .block-desc .container {
    max-width: 75%;
    padding: 0 5rem 0 0;
  }
}

@media screen and (min-width: 992px) {
  .block-desc {
    font-size: 1rem;
    line-height: 28px;
    margin-top: -35vh;
  }
}

@media screen and (min-width: 1200px) {
  .block-desc {
    display: flex;
    justify-content: center;
    margin-top: -40vh;
  }

  .block-desc .container {
    padding: 0 10rem 0 0;
  }
}

@media screen and (min-width: 1400px) {
  .block-desc {
    line-height: 1.9vw;
    font-size: 1.4rem;
    margin-top: -45vh;
  }

  .block-desc .container {
    max-width: 80%;
    padding: 0 20rem 0 0;
  }
}

/* ZONES */
.zones {
  position: relative;
  z-index: 2;
}

.zones .zones-bg {
  display: none;
}

.zones .container {
  padding: 0;
}

.zones article {
  margin-top: 2.5rem;
  padding-left: 2.5rem;
  position: relative;
}

.zones article:nth-child(even) {
  text-align: right;
  padding-left: 0;
  padding-right: 2.5rem;
}

@media screen and (min-width: 576px) {
  .zones {
    overflow: hidden;
    position: relative;
    margin-top: 5rem;
    margin-bottom: -3rem;
    z-index: 0;
  }

.zones .zones-bg {
    display: inline-block;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: calc(100vw* 1.2);
    background-image: url('.webp?rlkey=ihans0tn7dlm4v4c2lrhnyfa0&st=jl91itao&raw=1');
    background-repeat: no-repeat;
    background-size: cover;
    will-change: transform;
  }

  .zones article {
    margin-top: 8rem;
    will-change: transform;
  }
}

@media screen and (min-width: 1400px) {
  
  .zones {
    margin-top: 0;
  }
}


/* block-img-bottom */
.block-img-bottom {
  height: calc(100vw* 1.6);
  width: auto;
  background-image: url(".webp?rlkey=nphbrwu55p1sv02583ms08hy9&st=93xi3n4p&raw=1");
  background-repeat: no-repeat;
  background-size: cover;
  position: relative;
  z-index: 1;
  margin-top: -15rem;
}

@media screen and (min-width: 576px) {
  .block-img-bottom {
    height: calc(100vw* 0.6);
    background-image: url(".webp?rlkey=og6pxmowaqikv2mi7cn9sbfek&st=l0y92ly5&raw=1");
    background-repeat: no-repeat;
    background-size: cover;
    margin-top: 0;
    z-index: -1;
  }
}
<!DOCTYPE html>
<html lang="uk">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>БіоРитм</title>
    <meta property="og:title" content="БіоРитм">
    <meta property="og:type" content="website">
    <meta property="og:url" content="{{ url_for('main.index', _external=True) }}">
    <meta property="og:image" content="{{ url_for('static', filename='img/mob/img-1.webp') }}">
    <meta property="og:description" content="Незабаром ми змінимо ритм життя">

    <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='img/favicon-32x32.ico') }}" sizes="32x32">
    <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='img/favicon-192x192.ico') }}"
        sizes="192x192">
    <link rel="apple-touch-icon" href="{{ url_for('static', filename='img/favicon-192x192.ico') }}">

    <link rel="preconnect" href="">
    <link rel="preconnect" href="" crossorigin>
    <link href=":[email protected]&display=swap" rel="stylesheet">
    <script src="/[email protected]/dist/gsap.min.js"></script>
    <script src="/[email protected]/dist/ScrollTrigger.min.js"></script>
    <script src="/[email protected]/dist/ScrollToPlugin.min.js"></script>
</head>
<body>
    <main class="main">
        <div class="section-top">
            <section class="welcome">
            </section>
            <section class="block-desc animated-element">
                <div class="container">
                    <p>
                        Це саме те, на що Ви чекали… Все, що ви любите, що робить життя комфортним і натхненним, тепер
                        поєднано в одному місці. Вишуканий рівень, продумані до дрібниць планування, сміливі
                        архітектурні рішення та інфраструктура, що підлаштовується під ваш ритм.
                    </p>
                </div>
            </section>
        </div>
        <section class="zones">
          <div class="zones-bg"></div>
            <div class="container">
                <article class="pool-spa">
                    <div class="inside-wrap-article">
                        <h3 class="animated-element"><span class="text-blue">Твої</span> басейни та спа зона на вершині
                            міста</h3>
                        <picture>
                            <source srcset=".webp?rlkey=64jm9dqxgoovi10b69p2crcn3&st=yi025a75&raw=1"
                                media="(min-width: 576px)">
                            <img src=".webp?rlkey=yggqes2hnw4a2fyef9vfvjtqm&st=ecgrbs7m&raw=1" alt="Spa and poll"
                                class="main-img animated-element">
                        </picture>
                    </div>
                </article>
                <article class="fitness-roof">
                    <div class="inside-wrap-article">
                        <h3 class="animated-element"><span class="text-yellow">Твій</span> фітнес на краю неба</h3>
                        <picture>
                            <source srcset=".webp?rlkey=1dchmn44wfa862stpv64x71yg&st=mbsrfqx2&raw=1"
                                media="(min-width: 576px)">
                            <img src=".webp?rlkey=wusxpb632d62vzx4d5c8alsrl&st=3riucaiz&raw=1" alt="Fitness roof"
                                class="main-img animated-element">
                        </picture>
                    </div>
                </article>
            </div>
        </section>
        <section class="block-img-bottom">
        </section>
    </main>
</body>
</html>
发布评论

评论列表(0)

  1. 暂无评论