ElementorWordPressJavaScriptVýkonMobilná optimalizácia

Oprava pádov mobilných prehliadačov v Elementor karuseloch s viacerými autoplay videami

Naučte sa používať Intersection Observer na lazy-loading videí a predchádzanie pádom mobilných prehliadačov v Elementor karuseloch s viacerými automaticky prehrávanými videami.

Milan PavlákMilan Pavlák
7 min čítania
Oprava pádov mobilných prehliadačov v Elementor karuseloch s viacerými autoplay videami

Keď umiestnite niekoľko automaticky prehrávaných videí do animovaného Elementor karuselu (najmä rozloženia ako dvojstĺpcové vertikálne karusely s opačnými smermi posúvania), mobilné zariadenia a tablety často nedokážu zvládnuť takúto záťaž.

Typické príznaky zahŕňajú:

  • zamrznutie alebo pád mobilného prehliadača
  • výrazné poklesy FPS
  • oneskorená reakcia na scroll alebo dotyk
  • súčasné načítanie všetkých videí, ktoré zahltí pamäť/CPU
  • nekonzistentné správanie autoplay

Dôvodom je, že každý element <video> v karuseli sa pokúša:

  • načítať celý zdrojový súbor
  • dekódovať súbor
  • spustiť autoplay hneď, ako sa objaví v DOM

Na stránke so 6 + 6 videami v neustálom pohybe sa to stáva výkonnostným úzkym hrdlom, najmä na iOS a strednej triede Android zariadení.

Na vyriešenie tohto problému potrebujeme inteligentnejší systém.


Inteligentnejší prístup: Lazy-loading + automatické pozastavenie pomocou Intersection Observer

Nasledujúci skript rieši všetky hlavné problémy tým, že:

  • Načítava videá len vtedy, keď sú skutočne viditeľné (50 % vo viewport)
  • Pozastavuje a odstraňuje videá, keď opustia viewport
  • Znižuje spotrebu RAM odstránením src, keď nie je potrebný
  • Predchádza súčasnému dekódovaniu viacerých videí
  • Spúšťa sa iba na mobiloch a tabletoch (≤ 1024px)
  • Funguje globálne pre všetky Elementor videá (video.elementor-video)

Výsledkom je:

  • plynulé scrollovanie
  • žiadne pády prehliadača
  • stabilný výkon na mobiloch
  • autoplay videí len vtedy, keď je to vhodné
  • plynulý chod karuselov aj s mnohými videami

Skript

Nižšie je presný optimalizovaný skript, ktorý môžete použiť:

<script>
document.addEventListener("DOMContentLoaded", function() {
  // Run only on Elementor mobile + tablet (<= 1024px)
  if (window.innerWidth > 1024) {
    return;
  }

  /* ---------------------------------------
     Lazy-load + pause videos outside viewport
     (GLOBAL - applies to all Elementor videos)
     --------------------------------------- */
  var allVideos = document.querySelectorAll("video.elementor-video");

  allVideos.forEach(function(video) {
    if (!video.getAttribute("data-src")) {
      video.setAttribute("data-src", video.getAttribute("src"));
    }
    video.removeAttribute("src");
    video.setAttribute("preload", "none");
    video.isIntersecting = false;
  });

  var loadTimeouts = new Map();
  var unloadTimeouts = new Map();
  var observerOptions = { root: null, threshold: 0.5 };

  var observer = new IntersectionObserver(function(entries) {
    entries.forEach(function(entry) {
      var video = entry.target;
      video.isIntersecting = entry.isIntersecting;

      if (entry.isIntersecting) {
        // Cancel unload
        if (unloadTimeouts.has(video)) {
          clearTimeout(unloadTimeouts.get(video));
          unloadTimeouts.delete(video);
        }

        // Schedule load and play
        if (!loadTimeouts.has(video)) {
          var timer = setTimeout(function() {
            if (video.isIntersecting) {
              if (!video.getAttribute("src")) {
                video.setAttribute("src", video.getAttribute("data-src"));
                video.load();
              }
              video.play().catch(function(error) {
                console.error("Error auto-playing video:", error);
              });
            }
            loadTimeouts.delete(video);
          }, 300);

          loadTimeouts.set(video, timer);
        }
      } else {
        // Cancel load
        if (loadTimeouts.has(video)) {
          clearTimeout(loadTimeouts.get(video));
          loadTimeouts.delete(video);
        }

        // Schedule pause + unload src
        if (!unloadTimeouts.has(video)) {
          var timer2 = setTimeout(function() {
            if (!video.isIntersecting) {
              video.pause();
              video.removeAttribute("src");
            }
            unloadTimeouts.delete(video);
          }, 50);

          unloadTimeouts.set(video, timer2);
        }
      }
    });
  }, observerOptions);

  // Observe all videos
  allVideos.forEach(function(video) {
    observer.observe(video);
  });
});
</script>

Rozbor kódu: Ako skript funguje

Prejdime si kľúčové časti skriptu, aby ste ho mohli s istotou upraviť alebo použiť v iných projektoch.

1. Predčasné ukončenie na desktope

if (window.innerWidth > 1024) {
  return;
}

Túto optimalizáciu potrebujeme len na mobiloch a tabletoch. Desktopové zariadenia zvyčajne zvládajú viacero videí lepšie a možno budete chcieť, aby sa tam prehrávali automaticky. Čokoľvek širšie ako 1024px jednoducho preskočí celú logiku.


2. Príprava všetkých Elementor videí na lazy-loading

var allVideos = document.querySelectorAll("video.elementor-video");

allVideos.forEach(function(video) {
  if (!video.getAttribute("data-src")) {
    video.setAttribute("data-src", video.getAttribute("src"));
  }
  video.removeAttribute("src");
  video.setAttribute("preload", "none");
  video.isIntersecting = false;
});

Tu robíme nasledovné:

  • vyberieme každé video.elementor-video na stránke
  • presunieme pôvodný src do data-src
  • vymažeme src, aby prehliadač súbor ešte nenačítal
  • nastavíme preload="none", aby prehliadač nič nepredbufferoval

Od tohto momentu sú videá efektívne len zástupné prvky, kým nevstúpia do viewport.


3. Sledovanie časovačov načítania/odstránenia pre každé video

var loadTimeouts = new Map();
var unloadTimeouts = new Map();
var observerOptions = { root: null, threshold: 0.5 };

Používame dva objekty Map na uloženie ID setTimeout pre každé video:

  • loadTimeouts → oneskorené načítanie a prehrávanie, keď sa video stane viditeľným
  • unloadTimeouts → oneskorené pozastavenie a odstránenie, keď opustí viewport

threshold: 0.5 znamená, že callback sa spustí, keď je 50 % videa viditeľných.


4. IntersectionObserver: rozhodovanie o načítaní alebo odstránení

var observer = new IntersectionObserver(function(entries) {
  entries.forEach(function(entry) {
    var video = entry.target;
    video.isIntersecting = entry.isIntersecting;

    if (entry.isIntersecting) {
      // ... handle load logic ...
    } else {
      // ... handle unload logic ...
    }
  });
}, observerOptions);

IntersectionObserver sleduje každé video a informuje nás, keď:

  • vstúpi do viewport (≥ 50 % viditeľné)
  • opustí viewport

Namiesto neustáleho manuálneho kontrolovania pozície scrollu nás prehliadač efektívne upozorní.


5. Keď sa video stane viditeľným

if (entry.isIntersecting) {
  // Cancel unload
  if (unloadTimeouts.has(video)) {
    clearTimeout(unloadTimeouts.get(video));
    unloadTimeouts.delete(video);
  }

  // Schedule load and play
  if (!loadTimeouts.has(video)) {
    var timer = setTimeout(function() {
      if (video.isIntersecting) {
        if (!video.getAttribute("src")) {
          video.setAttribute("src", video.getAttribute("data-src"));
          video.load();
        }
        video.play().catch(function(error) {
          console.error("Error auto-playing video:", error);
        });
      }
      loadTimeouts.delete(video);
    }, 300);

    loadTimeouts.set(video, timer);
  }
}

Čo sa tu deje:

  • zrušíme akékoľvek čakajúce odstránenie (pre prípad, že používateľ rýchlo scrollne späť)
  • naplánujeme oneskorené načítanie a prehrávanie (300ms)
  • znova skontrolujeme, či je video stále v zornom poli pred načítaním (vyhneme sa zbytočnej práci)
  • obnovíme src z data-src, zavoláme .load() a potom .play()

Oneskorenie zabraňuje načítaniu príliš veľkého počtu videí naraz počas rýchleho scrollovania.


6. Keď video opustí viewport

// Cancel load
if (loadTimeouts.has(video)) {
  clearTimeout(loadTimeouts.get(video));
  loadTimeouts.delete(video);
}

// Schedule pause + unload src
if (!unloadTimeouts.has(video)) {
  var timer2 = setTimeout(function() {
    if (!video.isIntersecting) {
      video.pause();
      video.removeAttribute("src");
    }
    unloadTimeouts.delete(video);
  }, 50);

  unloadTimeouts.set(video, timer2);
}

Keď video zmizne zo zorného poľa:

  • akékoľvek čakajúce načítanie sa zruší (už ho nie je potrebné načítavať)
  • naplánujeme veľmi krátky timeout (50ms) na:
    • pause() videa
    • opätovné odstránenie jeho src → uvoľnenie pamäte a zastavenie bufferovania

Práve tu dochádza k skutočným úsporám RAM a CPU.


7. Spustenie pozorovania všetkých videí

allVideos.forEach(function(video) {
  observer.observe(video);
});

Nakoniec sa každé Elementor video pripojí k IntersectionObserver, čím sa celý systém stáva plne automatickým.

Žiadne zmeny widgetov, žiadne extra atribúty. Skript jednoducho funguje nad vaším existujúcim dizajnom.


Prečo tento skript funguje tak dobre

1. Intersection Observer riadi načítanie na základe viditeľnosti

Prehliadač načítava a prehráva videá len vtedy, keď je viditeľných aspoň 50 % elementu.

Ideálne pre pohybujúce sa karusely, kde videá plynulo vchádzajú a odchádzajú zo zorného poľa.

2. Odstránenie atribútu src videa drasticky znižuje spotrebu pamäte

Keď videá nie sú potrebné, skript odstráni ich atribút src.

To znamená:

  • žiadne bufferovanie
  • žiadne dekódovanie
  • žiadna spotreba RAM
  • žiadne využívanie GPU

3. Oneskorené načítanie predchádza špičkám CPU

setTimeout(..., 300) zabezpečuje, že prehliadač sa nepokúsi načítať príliš veľa videí naraz.

4. Okamžité odstránenie predchádza lagom

Keď video opustí viewport, pozastavíme ho a odstránime po 50ms.

5. Ľahký, čistý vanilla JavaScript

Žiadne závislosti. Žiadne výkonnostné náklady.

6. Funguje pre VŠETKY Elementor videá automaticky

Nie je potrebné upravovať widgety. Stačí pripojiť a funguje.


Ideálne prípady použitia

Tento skript je navrhnutý špeciálne pre rozloženia s výrazným pohybom, ako napríklad:

  • Vertikálne karusely s autoplay
  • Viacstĺpcové video mriežky s animáciou pri scrollovaní
  • Sekcie s video pozadím s čiastočnou viditeľnosťou
  • Opakujúce sa promo videá v slideroch
  • Dlhé stránky s mnohými Elementor video widgetmi

Ak vaše rozloženie obsahuje:

  • pohybujúce sa videá,
  • autoplay slučky a
  • viac ako 3 videá,

...tento skript je pre mobilných používateľov nevyhnutný.


Záverečné myšlienky

Predvolené video widgety Elementoru neobsahujú lazy-loading, riadenie na základe viditeľnosti ani optimalizáciu RAM. Na desktope je to zvládnuteľné, ale mobilné zariadenia môžu byť rýchlo preťažené.

Tento skript pridáva chýbajúcu logiku:

  • inteligentné načítanie
  • inteligentné odstránenie
  • automatické pozastavenie
  • sledovanie viewport

Vaši návštevníci získajú:

  • plynulý výkon
  • žiadne zamrznutia
  • plnú interaktivitu

A vaše videá sa naďalej automaticky prehrávajú len vtedy, keď majú.

Ak riešite podobné problémy s výkonom, pozrite si moje služby Elementor vývoja a optimalizácie výkonu webov.

Spojme sa

Chcete sa porozprávať o vašom projekte? Ozvite sa mi cez ktorýkoľvek z týchto kanálov.

Sídlo v Bratislave, Slovensko. K dispozícii pre projekty po celom svete.

Try me — I'm alive
Oprava pádov mobilných prehliadačov v Elementor karuseloch s viacerými autoplay videami