YouTube veya Vimeo embed'leri sayfa açılışında onlarca üçüncü taraf isteği getirir. Facade pattern thumbnail ve oynat düğmesiyle bu yükü tıklamaya erteler; birkaç düzine satır HTML, CSS ve vanilla JS yeterli.

Video Embed Yerine Facade Pattern: Uygulama Rehberi

Sayfanıza bir YouTube videosu gömmek teknik olarak birkaç satır kod. O <iframe> DOM'a yerleştiği anda tarayıcı arka planda işe koyuluyor: YouTube sunucularına DNS sorgusu, TCP ve TLS el sıkışmaları, ardından oynatıcı JavaScript paketi, reklam sistemi modülleri ve izleme scriptleri. Kullanıcı videoyu hiç izlemeden sayfayı kapasa bile bu yük tarayıcıya ulaşmış oluyor.

Facade pattern bu soruna pratik bir yanıt verir. Gerçek <iframe> yerine thumbnail görsel ve oynat düğmesinden oluşan hafif bir placeholder tutarsınız; kullanıcı düğmeye tıkladığında JavaScript iframe'i oluşturur, kaynağı atar ve oynatıcı o anda yüklenmeye başlar. Kullanıcı zaten izlemek istediğini belirttiği için gecikme algılanmaz, üçüncü taraf yükü ise sayfa açılışından çıkmış olur.

Senaryo somut olsun: bir ürün sayfasında tanıtım videosu var, mobil kullanıcıların büyük çoğunluğu videoyu izlemeden çıkıyor ama yük her seferinde geliyor. Facade pattern bu yükü tıklamaya ertelemenin doğrudan ve bakımı kolay yöntemi.

Bir YouTube embed'i sayfaya ne getirir?

Standart YouTube embed kodu sayfaya eklendiğinde tarayıcı önce youtube.com, ardından googlevideo.com ve reklam altyapısı için ek etki alanlarına bağlanır. Her yeni etki alanı için DNS çözümleme, TCP el sıkışması ve TLS müzakeresi gerekir. Bu bağlantı maliyeti onlarca milisaniye alır; düşük bağlantılı veya yüksek gecikmeli mobil ağlarda bu süre yüzlerce milisaniyeye çıkabilir.

İndirilen kaynaklar arasında oynatıcı kütüphanesi, küçük resim görselleri, reklam sistemi modülleri ve izleme scriptleri bulunur. Bunların tamamı ana iş parçacığında (main thread) çalışmak için yarışır; kullanıcı etkileşimlerine verilen yanıt süresi uzar. Sayfada birden fazla embed varsa her biri kendi bağlantı döngüsünü başlatır.

Kısa bir tanılama yapın. Tarayıcı geliştirici araçlarındaki Network sekmesini açın, sayfayı yükleyin ve YouTube alanına ait istekleri filtreleyin. Çoğu durumda tek bir embed için beş ila on farklı istek görürsünüz. Bazıları render-blocking olarak işaretlenir ve sayfanın boyamasını geciktirir. Sayfa başlangıcında bu yükü taşımak zorunlu değil.

Bir ön bağlantı (rel="preconnect") alternatif gibi görünebilir ama yalnızca bağlantı maliyetini öne çeker, kaynakları indirmeyi ertelemez. Yük yine de gelir. İzlenme oranı düşük videolarda bu yetmez.

Facade pattern'in çalışma mantığı

Facade (cephe) deseninin özü şu: kullanıcıya gerçek bileşenin yerinde onun görsel temsilini gösterirsiniz, işlevsel bileşen ancak gerekli olduğunda devreye girer. Video embed bağlamında bu üç adıma indirgenir. Birincisi, video ID'sini alıp YouTube thumbnail URL'ini oluşturursunuz ve bunu bir <img> etiketiyle sayfaya koyarsınız. İkincisi, üzerine tıklanabilir bir oynat düğmesi eklersiniz. Üçüncüsü, tıklama olduğunda JavaScript devreye girer, thumbnail ve düğmeyi kaldırır ve gerçek <iframe>'i o konuma yerleştirir.

Üçüncü taraf kaynaklarına yapılan istekler sayfa yüklenirken değil, tıklama anında başlar. Sayfanın ilk boyaması (FCP) ve en büyük içerik boyaması (LCP) bu yükten arınmış olur. Kullanıcı videoyu açmadığında iframe kaynağı hiç indirilmez.

Bant genişliği nereye gider? Thumbnail görsele. O da gerekli: kullanıcının ne bulduğunu görmesi gerekir. YouTube hqdefault.jpg yaklaşık 15-25 KB aralığında; bunu WebP'ye çevirip sıkıştırırsanız daha küçük tutabilirsiniz. Oynat düğmesi CSS ile çizilirse ek istek sıfır.

Kullanıcı fark eder mi? Hayır. Oynatıcı birkaç saniye içinde hazır olur ve kullanıcı zaten izlemek istediğini düğmeye basarak belirtmiştir. Ağır bir sonraki sayfaya geçerken yaşanan beklemeyle karşılaştırılamaz.

Temel HTML ve CSS yapısı

İskelet mümkün olduğunca yalın olsun. Video konteyneri için bir div, içinde thumbnail img ve bir oynat button yeterli:

<div class="video-facade" data-videoid="VIDEO_ID">
  <img
    src="https://i.ytimg.com/vi/VIDEO_ID/hqdefault.jpg"
    alt="Video başlığı"
    loading="lazy"
    decoding="async"
    width="640"
    height="360"
  >
  <button class="video-facade__play" aria-label="Videoyu oynat" type="button">
    <svg viewBox="0 0 68 48" aria-hidden="true" focusable="false">
      <path fill="#ff0000" d="M66.52 7.74C65.7 4.73 63.29 2.35 60.25 1.54
        54.9 0 33.9 0 33.9 0S12.9 0 7.56 1.54C4.52 2.35 2.1 4.73
        1.28 7.74 0 13.05 0 24 0 24s0 10.95 1.28 16.26c.82 3.01
        3.24 5.39 6.28 6.2C12.9 48 33.9 48 33.9 48s21 0 26.35-1.54
        c3.04-.81 5.45-3.19 6.27-6.2C68 34.95 68 24 68 24
        s0-10.95-1.48-16.26z"/>
      <path fill="#fff" d="M45.5 24 27.5 14v20z"/>
    </svg>
  </button>
</div>

CSS ile konteyneri oransal tutun; bu sayede hem masaüstünde hem mobilde taşmaz:

.video-facade {
  position: relative;
  cursor: pointer;
  background: #000;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.video-facade img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.video-facade__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
}

.video-facade__play svg {
  width: 68px;
  height: 48px;
  opacity: 0.9;
  transition: opacity 0.2s;
}

.video-facade:hover .video-facade__play svg {
  opacity: 1;
}

loading="lazy" thumbnail için uygun: video sayfa görünür alanının dışındaysa görsel de ertelenir. Video üst katlamada ve görünür alandaysa loading="eager" tercih edin; aksi halde LCP elemanı geç yüklenir ve skor düşer. width ve height atributları CLS'yi sıfırda tutar, tarayıcı görsel gelmeden önce alanı ayırır.

JavaScript: tıklamayla iframe oluşturma

Sayfadaki tüm facade konteynerlerini tarayıp tıklamayı dinleyen snippet:

document.querySelectorAll('.video-facade').forEach(function (facade) {
  facade.addEventListener('click', function () {
    var videoId = facade.dataset.videoid;
    var iframe = document.createElement('iframe');
    iframe.src =
      'https://www.youtube.com/embed/' + videoId + '?autoplay=1&rel=0';
    iframe.allow =
      'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture';
    iframe.allowFullscreen = true;
    iframe.loading = 'eager';
    iframe.title = facade.querySelector('img').alt;
    iframe.style.cssText =
      'position:absolute;inset:0;width:100%;height:100%;border:0';
    facade.innerHTML = '';
    facade.appendChild(iframe);
  });
});

Birkaç ayrıntı önemli. autoplay=1 kullanıcının tıkladığı için çalışır; tarayıcı kullanıcı etkileşimi olmaksızın otomatik oynatmayı bloke eder. rel=0 oynatıcının kapanış ekranında rastgele öneriler göstermesini kısıtlar; rakip içeriklerin ürün sayfanızda belirmesini istemiyorsanız bunu açık bırakmayın. iframe.title erişilebilirlik için zorunlu, ekran okuyucular bu değeri kullanır.

facade.innerHTML = '' thumbnail ve düğmeyi temizler, ardından iframe eklenir. Konteyner CSS'i position: relative içerdiğinden iframe position: absolute ile tam kaplar. Geçiş animasyonu eklemek isterseniz iframe opacity'sini 0'dan 1'e geçişle başlatabilirsiniz; ama çoğu durumda bu fazlalık, oynatıcı yüklenene kadar kısa bir siyah alan zaten doğal geçişi sağlar.

Klavye erişilebilirliği. <button> kullandığınız için Enter ve Space ile aktivasyon otomatik çalışır. <div> veya <span> tercih ettiyseniz tabindex="0" ve keydown (Enter, Space) dinlemesi eklemeniz gerekir; aksi halde klavye ve ekran okuyucu kullanıcıları videoyu açamaz.

Vimeo için uyarlama

Vimeo'nun thumbnail URL yapısı YouTube'dan farklı: doğrudan bir URL kalıbı yok, API üzerinden çekilmesi gerekiyor. Statik build veya SSG kullananlar için en pratik yol, derleme sırasında API'den thumbnail URL'ini alıp doğrudan src'ye yazmak. Dinamik siteler için ise sunucu tarafı proxy veya cache katmanı işi üstlenir.

Tıklama handler'ında provider'a göre dallanma yapın:

document.querySelectorAll('.video-facade').forEach(function (facade) {
  facade.addEventListener('click', function () {
    var provider = facade.dataset.provider || 'youtube';
    var videoId = facade.dataset.videoid;
    var src =
      provider === 'vimeo'
        ? 'https://player.vimeo.com/video/' + videoId + '?autoplay=1'
        : 'https://www.youtube.com/embed/' + videoId + '?autoplay=1&rel=0';
    var iframe = document.createElement('iframe');
    iframe.src = src;
    iframe.allow = 'autoplay; fullscreen; picture-in-picture';
    iframe.allowFullscreen = true;
    iframe.loading = 'eager';
    iframe.title = facade.querySelector('img').alt;
    iframe.style.cssText =
      'position:absolute;inset:0;width:100%;height:100%;border:0';
    facade.innerHTML = '';
    facade.appendChild(iframe);
  });
});

Vimeo'da gizlilik ayarı olan videolar için ?dnt=1 parametresi üçüncü taraf çerezlerini devre dışı bırakır; GDPR uyumu gereken durumlarda bunu ekleyin. HTML tarafında data-provider="vimeo" ve data-videoid atributları yeterli; geri kalan mantık JS'te aynı kalır.

Ne zaman işe yarar, ne zaman gereksiz, ne zaman ters etki?

İşe yarar. Sayfada bir veya birden fazla video var, kullanıcıların önemli bir kısmı videoyu açmadan ayrılıyor, video sayfanın kritik yolunda (critical path) oturuyor ve LCP ya da TBT skoru videonun tetiklediği üçüncü taraf yükü nedeniyle kötüleşiyor. Özellikle blog yazısı ortasına gömülmüş, kaydırılmadan görünmeyen video embed'ler için kazanç büyük olur.

Gereksiz durumlar da var. Video sayfanın birincil içeriğiyse, yani kullanıcı zaten izlemek için geliyorsa - bir kurs platformu, bir canlı yayın arşiv sayfası, bir video galeri - facade kullanıcıyı bir tıklama daha yapmaya zorlar ve oynatıcıyı geciktirir. Burada overhead kabul edilebilir; doğrudan yüklemek daha iyi hizmet verir.

Ters etki de mümkün. Thumbnail olarak yüksek çözünürlüklü ve sıkıştırılmamış görsel koyarsanız YouTube iframe'inden ağır bir yük yerleştirmiş olabilirsiniz. hqdefault.jpg makul boyuttadır; kendi sunucunuza indirip WebP'ye çevirirseniz daha iyi kontrol edersiniz. Ayrıca çok sayıda video olup her biri loading="lazy" olmadan yüklenirse thumbnail yığını da başlangıç yükünü şişirir. Üç veya daha fazla video içeren sayfalarda tüm thumbnail'lerin lazy olduğundan emin olun.

Peki ya üçüncü taraf izin (consent) yönetimi? Cookie banner'ınız izinsiz üçüncü taraf bağlantılarını engelliyorsa facade pattern bu uyumu kolaylaştırır: iframe yalnızca kullanıcı tıkladığında oluştuğu için, tıklama öncesinde kabul alınmış olabilir ya da yalnızca kabul sonrasında butonu etkinleştiren bir katman ekleyebilirsiniz.

Facade pattern üçüncü taraf embed'lerin neden olduğu başlangıç yükünü ortadan kaldırmanın bağımlılık gerektirmeyen, okunması kolay bir yolu. Birkaç düzine satır HTML, CSS ve vanilla JavaScript ile çalışır; ekstra kütüphane kurmak gerekmez. Güncellemesi de basit: video ID değişirse data-videoid'yi güncellersiniz, başka bir şey değişmez.

Facade pattern izlenme takibini doğrudan etkilemez. YouTube analitikleri kullanıcının oynatıcıyı başlattığı andan itibaren çalışmaya devam eder. Sayfa yüklendiğinde değil, tıklamayla tetiklendiği için sunucu log'larında embed isteği daha geç görünür; ama bu çoğu kullanım senaryosunda önem taşımaz.

Tek bir embed bile 15-20 üçüncü taraf isteği tetikleyebilir. Kritik yolda oturan embed için facade'ın faydası açıktır; her videolu sayfaya uygulamak gerekmez. İzlenme oranı düşük içeriklerde bu desen hem kullanıcıya hem performans skoruna hizmet eder.