Lazy-load SEO bez ztráty indexovatelnosti

Proč řešit lazy-load bez ztráty indexovatelnosti

Lazy-loading (odložené načítání) obrázků a videí je dnes standardem pro zrychlení načítání stránek, snížení přenosu dat a zlepšení Core Web Vitals. Při nesprávné implementaci však hrozí, že vyhledávače neobjeví nebo nepochopí vizuální zdroje, což snižuje viditelnost v Obrázcích/Ve Videích Google, zhoršuje porozumění obsahu a může poškodit výkon ve Snippetech, Discover či ve video rich results. Tento článek představuje techniky, vzory a kontrolní seznam, jak provádět lazy-load správně, bez kompromisů v indexovatelnosti.

Indexovatelnost vizuálů: jak ji vyhledávače posuzují

  • Dostupné HTML elementy: <img>, <picture>, <video>, <source>, <iframe> (pro embedy).
  • Jednoznačné adresy: crawlable URL v atributech src/srcset/poster/data-* (při JS lazy-loadu nutný fallback).
  • Kontext a textové signály: alt texty, figcaption, okolní text, nadpisy; pro video také thumbnail, přepis a strukturovaná data.
  • Strukturovaná data: ImageObject a VideoObject podle schema.org (JSON-LD) s contentUrl, thumbnailUrl, uploadDate, duration.
  • Sitemapy: image a video rozšíření v XML sitemapách na podporu objevení.

Kdy (ne)lazy-loadovat: pravidlo „nad záhybem“ a LCP

  • Nelazy-loadujte LCP obrázek: hero obrázek nad záhybem by měl mít loading="eager" (výchozí) a volitelně fetchpriority="high".
  • Lazy-loadujte vše mimo viewport: galerie, ilustrační obrázky dále v textu, embedovaná videa mimo první obrazovku.
  • Střední hranice: prvky těsně pod záhybem; zvažte threshold v IntersectionObserver nebo prefetch.

Preferovaná volba: nativní lazy-load

Moderní prohlížeče podporují nativní lazy-load pro <img> a <iframe>:

<img src="obr.jpg" alt="Popis" width="1200" height="800" loading="lazy" decoding="async">
<iframe src="https://player.example/video" title="Video" loading="lazy"></iframe>

  • Výhody: jednoduché, stabilní, bez JS, spolehlivé pro indexovatelnost (pokud src existuje v HTML).
  • Požadavky: vždy definujte width a height pro prevenci CLS; používejte decoding="async" pro off-main-thread dekódování.

JS lazy-load s IntersectionObserverem (bez ztráty indexace)

Pokud potřebujete vlastní logiku (fade-in, blur-up, měření):

  1. Serverovým výstupem by mělo být plnohodnotné <img> s validním src (nikoli prázdné!) a loading="lazy". JS pak může zdroj „vyměnit“ za vyšší rozlišení nebo WebP/AVIF dle potřeby.
  2. Alternativně použijte data-src/data-srcset, ale přidejte noscript fallback s identickým <img src=…> blokem, aby byl zdroj objevitelný i bez JS.

Příklad HTML s fallbackem (bez <pre>):

<img class="lazy" data-src="obr.webp" src="obr-low.jpg" alt="Popis" width="1200" height="800" loading="lazy" decoding="async">
<noscript><img src="obr.webp" alt="Popis" width="1200" height="800"></noscript>

Klíčové zásady:

  • Vyhněte se „phantom“ elementům: nikdy nevypisujte pouze prázdný <div data-src>. Použijte reálný <img> nebo <picture>.
  • „Low-quality placeholder“ (LQIP/blur-up): src může být malý progresivní JPEG/blur data-uri, který později nahradíte skutečným data-src.
  • Bezpečná výměna atributů: při intersectu přesuňte data-src → src a data-srcset → srcset, ponechte loading="lazy" pro zpětnou kompatibilitu.

Responsivní obrázky (picture, srcset, sizes)

Pro správný výběr formátu a šířky:

<picture>
  <source type="image/avif" srcset="obr-800.avif 800w, obr-1600.avif 1600w" sizes="(max-width: 800px) 100vw, 800px">
  <source type="image/webp" srcset="obr-800.webp 800w, obr-1600.webp 1600w" sizes="(max-width: 800px) 100vw, 800px">
  <img src="obr-800.jpg" srcset="obr-800.jpg 800w, obr-1600.jpg 1600w" sizes="(max-width: 800px) 100vw, 800px" alt="Popis" width="800" height="533" loading="lazy" decoding="async">
</picture>

  • Indexovatelnost: Google rozumí <picture>. Důležité je, aby finální <img> obsahoval alt a generované src/srcset byly crawlable.
  • Preferujte moderní formáty: AVIF a WebP jako první <source>, JPEG jako fallback v <img>.

Priority načítání a Core Web Vitals

  • LCP obrázek: fetchpriority="high", preload pokud je kritický, loading ponechat „eager“.
  • CLS: vždy definujte width a height (nebo aspect-ratio v CSS). Neměňte rozvržení při nahrazení placeholderu.
  • INP/TBT: vyhněte se těžkým JS lazy-load knihovnám; preferujte nativní lazy-load nebo lehký IntersectionObserver.

Lazy-load videí: HTML5 video vs. platformové embedy

HTML5 video:

  • Element: <video controls preload="metadata" poster="thumb.jpg" width="1280" height="720"><source src="video.mp4" type="video/mp4"></video>
  • Lazy-load: video soubor se nenačte celý s preload="metadata"; pro odložené načtení mimo viewport použijte IntersectionObserver a odložené vložení <source> nebo nastavení src až při intersectu s noscript fallbackem.
  • Indexovatelnost: používejte VideoObject se contentUrl (přímý MP4/HLS), thumbnailUrl, name, description, uploadDate, duration.

YouTube/Vimeo embed:

  • Natívně: <iframe loading="lazy" src="https://www.youtube.com/embed/ID" title="…" width="560" height="315" allow="accelerometer; autoplay; encrypted-media" allowfullscreen></iframe>
  • „Lite“ komponenty: pokud používáte „lite“ iframe (placeholder + JS), vždy přidejte <noscript> s plným <iframe>, aby byl embed objevitelný a prohledávač měl přímou stopu na embedUrl.
  • Strukturovaná data: VideoObject s embedUrl, thumbnailUrl (statický obrázek), description. Přidejte také transcript jako textový obsah stránky.

Noscript fallbacky: kdy a jak

  • Obrázky: při JS lazy-loadu používejte <noscript><img src="plny-zdroj.jpg" alt="…" width="…" height="…" /></noscript>.
  • Videa/embedy: <noscript><iframe src="…/embed/ID"></iframe></noscript> nebo přímý odkaz na video stránku.
  • Obsah v noscript: měl by zrcadlit reálný obsah, nikoli být prázdný. Zabezpečujete tím indexovatelnost při vypnutém JS nebo opožděném renderu.

Strukturovaná data pro obrázky a videa

Přidejte JSON-LD (stručně, bez <pre>; zalomené řádky):

<script type="application/ld+json">
{
"@context":"https://schema.org","@type":"Article","image":{
"@type":"ImageObject","url":"https://example.com/obr-1600.jpg","width":1600,"height":900,"caption":"Popis obrázku"}
}
</script>

Pro video:

<script type="application/ld+json">
{ "@context":"https://schema.org","@type":"VideoObject","name":"Název",
"description":"Popis","thumbnailUrl":"https://example.com/thumb.jpg",
"uploadDate":"2025-09-01","duration":"PT2M10S",
"contentUrl":"https://cdn.example.com/video.mp4","embedUrl":"https://www.youtube.com/embed/ID" }
</script>

CDN, optimalizace a formáty

  • On-the-fly transformace: CDN (Image CDN) pro generování šířek a formátů AVIF/WebP podle Accept hlavičky.
  • Komprese a profily: pro fotografie: AVIF/WebP; pro vektorovou grafiku: SVG (nelazy-loadujte kritické SVG ikony, vložte inline). Pro screencasty: MP4/H.264 nebo H.265 s přiměřeným bitrate, + samostatný thumbnail.
  • Cache: dlouhá Cache-Control s fingerprintováním názvů, immutable pokud možno.

Časté chyby, které zabíjejí indexovatelnost

  1. Žádný src v HTML (pouze data-src bez noscript) – crawler bez renderu nic nenajde.
  2. Lazy-load LCP obrázku: dramatické zhoršení LCP a nestabilní indexace obrázků v hero sekci.
  3. Skryté či prázdné <img>: CSS display:none nebo wrapper s nulovou velikostí; crawler obrázek ignoruje.
  4. Blokované CDN URL v robots.txt – obrázky/videa nejsou crawlable.
  5. Chybějící rozměry: způsobuje CLS a degradaci hodnocení.
  6. Těžký JS lazyloader: zhoršení INP/TBT, zejména na mobilech.

Měření dopadu: metriky a logy

  • Core Web Vitals: LCP obrázek načten včas, nulové nebo nízké CLS, stabilní INP.
  • CrUX a RUM: reálná data uživatelů; sledujte LCP element (typicky <img>).
  • Search Console: Pokrytí, Vylepšení videa, Obrázky ve Skúmání.
  • Logy serveru/CDN: hity na obrázkové/video URL od botů (Googlebot-Image/Video).
  • Index Coverage pro média: počet indexovaných obrázků/videí, výskyt v rich výsledcích.

Testování a audit implementace

  1. View-source test: Zkontrolujte, zda jsou ve statickém HTML přítomny elementy <img>/<video>/<iframe> s reálnými URL nebo noscript fallbacky.
  2. „Bez JS“ render: Spusťte stránku s vypnutým JS – zobrazí se obrázky alespoň přes noscript?
  3. Lighthouse a web-vitals: LCP, CLS, INP; identifikujte LCP element a jeho atributy (rozměry, loading, fetchpriority).
  4. URL Inspection: Ověřte, zda Google vidí video a vytahuje thumbnail; validujte VideoObject/ImageObject.
  5. Robots a cache: CDN/obrázkové/videá URL musí být povolené a vracet kód 200; správné hlavičky.

Vzory pro různé scénáře

Hero (bez lazy-loadu):
<img src="/img/hero-1600.avif" alt="Produkt v akci" width="1600" height