Sorun
Dokümanlar arası görünüm geçişleri, aynı kaynaklı gezinme sırasında iki sayfa arasındaki öğeleri canlandırır. Tarayıcı, eski sayfanın anlık görüntüsünü alır, gezinir ve ardından anlık görüntüden yeni sayfaya animasyon ekler. Yeni sayfa; stil sayfaları, düzen komut dosyaları veya önemli DOM öğeleri gibi kritik kaynakları yüklemeyi tamamlamadıysa geçiş, eksik veya stillendirilmemiş bir duruma animasyon uygular. Bu durum, öğelerin yanlış konumlara dönüşmesi, içeriğin animasyonun ortasında yeniden düzenlenmesi veya geçiş tamamlandıktan sonra yedek yazı tiplerinin web yazı tiplerine dönüşmesi gibi görsel hatalara neden olur.
Çözüm
Yeni sayfanın <head> bölümündeki kritik <link> ve <script> öğelerinde blocking="render" kullanın ve belirli DOM öğeleri ayrıştırılana kadar oluşturmayı engellemek için <link rel="expect"> kullanın. Bu sayede tarayıcı, yeni sayfanın görsel durumu kararlı hale gelene kadar görüntüleme geçişi animasyonunu başlatmaz. Tarayıcı, arka planda HTML'yi ayrıştırmaya devam eder. Yalnızca boyama ertelenir.
Uygulama Stratejisi
- ZORUNLU: Her iki sayfada da
@view-transitionCSS kuralıyla dokümanlar arası görünüm geçişlerini etkinleştirin. - ZORUNLU: Kritik stil sayfalarının
<head>içinde olduğundan emin olun.<head>içindeki stil sayfaları varsayılan olarak oluşturmayı engeller. Dinamik olarak eklenen stil sayfaları için açıkçablocking="render"gerekir. - Geçiş animasyonundan önce yürütülmesi gereken öğelerde (ör. tema uygulayan veya düzeni etkileyen komut dosyaları)
blocking="render"öğesini<script>KULLANIN. - Ekranın üst kısmındaki içerik ayrıştırılana kadar oluşturmayı engellemek için
<link rel="expect" href="#element-id" blocking="render">KULLANIN. Bu, tüm geçiş türleri için geçerlidir: tam sayfa çapraz geçişler (boş bir sayfaya animasyon eklemeyi önlemek için), şekil değiştirme animasyonları (adlandırılmış öğelerin DOM'da mevcut olduğundan emin olmak için) ve komut dosyasına bağlı düzenler (stilli içeriğin ayrıştırıldığından emin olmak için). - Kritik olmayan içeriklerin oluşturulmasını ENGELLEMEYİN. Yalnızca ilk görüntü alanını etkileyen kaynakları ve öğeleri engelleyin. Çok fazla içeriğin engellenmesi geçişi geciktirir ve algılanan performansı düşürür.
Uygulama Kılavuzu
1. adım: Belgeler arası görünüm geçişlerini etkinleştirme
ZORUNLU: Hem kaynak hem de hedef sayfalarda @view-transition kuralı bulunmalıdır. Bu olmadan dokümanlar arası geçiş gerçekleşmez.
/*
MANDATORY: Include this rule in every page that participates
in cross-document view transitions.
`navigation: auto` enables transitions for standard navigations
(link clicks, form submissions, back/forward).
*/
@view-transition {
navigation: auto;
}
/* MANDATORY Copy-Paste Safety: Disable cross-document view transitions for users requesting reduced motion */
@media (prefers-reduced-motion: reduce) {
@view-transition {
navigation: none;
}
}
2. Adım: Kritik Komut Dosyaları Yürütülene Kadar Oluşturmayı Engelleyin
<head> içindeki engelleyici olmayan bir komut dosyasının, geçiş animasyonundan önce çalışması gerekiyorsa (ör. bir tema sınıfı uygulamak veya düzeni etkilemek için) bu komut dosyasını blocking="render" ile işaretleyin. Bu işlem yapılmazsa async, defer veya type="module" komut dosyaları geçiş başladıktan sonra yürütülebilir.
<head>
<!--
DO: Mark layout-critical scripts with blocking="render".
-->
<script type=module blocking="render">
// Example: apply a stored theme before the page renders,
// so the transition snapshot reflects the correct theme.
document.documentElement.dataset.theme =
localStorage.getItem('theme') || 'light';
</script>
</head>
3. Adım: Önemli DOM Öğeleri Ayrıştırılana Kadar Oluşturmayı Engelleyin
<head> içindeki stil sayfaları ve blocking="render" komut dosyaları yalnızca <head> öğesinin tamamen işlendiğini garanti eder. <body> içeriğinin ayrıştırılmasını beklemezler. Ek engelleme olmadan tarayıcı, ekranın üst kısmındaki öğeler DOM'da mevcut olmadan önce yeni sayfa anlık görüntüsünü alabilir. Bu da boş veya kısmen oluşturulmuş bir sayfaya animasyonlu bir geçişe neden olur.
<link rel="expect">, belirli bir öğe (id ile tanımlanır) ayrıştırılana kadar oluşturmayı engelleyerek bu sorunu çözer. href değeri, hedef öğenin id özelliğiyle eşleşen bir parça tanımlayıcı (ör. #hero) olmalıdır. Bu öğenin kapanış etiketi ayrıştırıldıktan sonra oluşturma engellemesi kaldırılır. <link rel="expect">, yalnızca hedef DOM öğesinin dokümanda mevcut olduğunu garanti eder. Harici alt kaynakların (ör. <img> pikseller) indirilmesini veya kodunun çözülmesini beklemez.
Aşağıdaki senaryoların tümünde <link rel="expect"> KULLANIN:
1. Kullanım Alanı: Tam Sayfa Çapraz Geçiş
Hiçbir öğede view-transition-name olmasa bile varsayılan root geçişi, sayfanın tamamını çapraz geçişle değiştirir. Yeni sayfanın anlık görüntüsü, ekranın üst kısmındaki içerik ayrıştırılmadan önce alınırsa çapraz geçiş, eski sayfadan boş veya eksik bir sayfaya animasyon uygular. Ekranın üst kısmında görünen içeriğin sonunu işaretleyen bir öğede oluşturmayı engelleme.
<head>
<link rel="stylesheet" href="/css/styles.css">
<!--
DO: Block rendering until the main content area is parsed,
even for a simple cross-fade. Without this, the browser may
snapshot the page before visible content exists in the DOM,
causing the cross-fade to reveal a blank or partial page.
-->
<link rel="expect" href="#main-content" blocking="render">
</head>
<body>
<header>...</header>
<main id="main-content">
<h1>Page Title</h1>
<p>Above-the-fold content the user should see immediately.</p>
</main>
<!-- Content below the fold does NOT need to be blocked on -->
<section>...</section>
</body>
2. Kullanım Alanı: Belirli Öğeler Arasında Şekil Değiştirme Animasyonları
Her iki sayfadaki öğeler bir view-transition-name paylaştığında tarayıcı, gezinme sırasında bu öğeleri sorunsuz bir şekilde dönüştürür. Geçiş başladığında hedef öğe ayrıştırılmamışsa tarayıcı bu öğeyi bulamaz. Bu durumda, şekil değiştirme işlemi ayrı çıkış ve giriş animasyonlarına indirgenir. view-transition-name içeren öğe ayrıştırılana kadar oluşturmayı engelleyin.
<link rel="expect">, oluşturma işlemini yalnızca hedef DOM öğesi ayrıştırılana kadar duraklattığından ve resim verilerinin indirilmesini veya kodunun çözülmesini beklemediğinden, önbelleğe alınmamış bir <img> yeni sayfa anlık görüntüsünde boş bir dikdörtgen olarak yakalanabilir. Resim geçişleri sırasında boş anlık görüntüleri veya düzen kaymalarını önlemek için kritik geçiş resimlerini önceden yükleyin veya önceden kodunu çözün (örneğin, <link rel="preload" as="image"> ile veya hedef sayfayı önceden oluşturarak) ve açık boyutlandırma yedekleri (width ve height özellikleri veya CSS aspect-ratio ve yer tutucu arka plan rengi) sağlayın.
<head>
<link rel="stylesheet" href="/css/styles.css">
<!--
DO: Preload critical transition images so their pixels are
available to decode before the new-page snapshot is captured.
<link rel="expect"> only waits for the DOM element to be parsed,
NOT for image pixels to download or decode.
-->
<link rel="preload" as="image" href="/img/product.webp" fetchpriority="high">
<!--
DO: Block rendering until the element participating in the
morph animation has been parsed. Without this, the browser
may start the transition before #hero exists, causing the
morph to degrade to a fade-out/fade-in.
-->
<link rel="expect" href="#hero" blocking="render">
<!--
When multiple blocking="render" resources are present,
rendering is blocked until ALL of them are satisfied.
Here, the browser waits for both the script to execute
AND the #hero element to be parsed — whichever comes last.
-->
<script async blocking="render" src="/js/transition-setup.js"></script>
</head>
<body>
<header>...</header>
<section id="hero">
<h1 style="view-transition-name: page-title">Product Name</h1>
<!--
DO: Provide explicit dimensions (width/height or aspect-ratio)
as a sizing fallback so the snapshot captures the correct layout
box even if image decoding is still in progress.
-->
<img
style="view-transition-name: hero-image"
src="/img/product.webp"
width="800"
height="600"
alt="Product"
>
</section>
</body>
4. adım: Oluşturmayı engelleyen duyarlı kaynaklar için medya sorgularını kullanma
Farklı görüntü alanı boyutları, ekranın üst kısmında farklı miktarlarda içerik gösterebilir. Yalnızca belirli bir görüntü alanı genişliğinde görünen içeriklerin oluşturulmasını engellemek için <link rel="expect"> öğesinde media özelliğini kullanın.
<head>
<!--
DO: Use media queries to conditionally block rendering.
On wide screens, both the hero and the sidebar are visible,
so block until both are parsed. On narrow screens, only the
hero is visible initially.
-->
<link
rel="expect"
href="#hero"
blocking="render"
media="screen and (width <= 768px)"
>
<link
rel="expect"
href="#sidebar"
blocking="render"
media="screen and (width > 768px)"
>
</head>
5. adım: Bağlama bağlı geçişler için pagereveal'i kullanın (isteğe bağlı)
pagereveal etkinliği, temel oluşturmayı engelleyen strateji için gerekli değildir. Yalnızca view-transition-name değerlerinin, kullanıcının nereden geldiğine göre dinamik olarak atanması gerektiğinde (ör. belirli bir liste öğesini ayrıntılar sayfası başlığına dönüştürme) gereklidir.
view-transition-name değerleri CSS'de statik olarak atanmışsa veya yalnızca varsayılan tam sayfa çapraz geçişi kullanıyorsanız bu adımı tamamen atlayın.
<head>
<!--
MANDATORY: The pagereveal listener must be registered before
the page renders. Inline small setup scripts with blocking="render"
to avoid an extra network round-trip on cold loads, or use an
external async script with blocking="render" so the listener is
registered early without blocking HTML parsing.
If the listener is registered too late (e.g., in a deferred
script), the event may have already fired.
-->
<script async blocking="render" src="/js/transition-setup.js"></script>
</head>
// transition-setup.js
window.addEventListener('pagereveal', async (event) => {
if (!event.viewTransition) return;
const from = navigation.activation?.from;
if (!from) return;
const fromUrl = new URL(from.url);
// DO: Assign view-transition-name based on navigation context.
// This enables a morph animation from the product card on the
// list page to the heading on the detail page.
if (fromUrl.pathname === '/products/') {
const heading = document.querySelector('main h1');
if (!heading) return;
heading.style.viewTransitionName = 'product-title';
try {
await event.viewTransition.ready;
} catch (error) {
// Skipped view transitions reject `ready` with InvalidStateError.
if (error.name !== 'InvalidStateError') {
throw error;
}
} finally {
// MANDATORY: Remove the temporary name after the transition
// finishes. Stale names interfere with subsequent navigations
// and prevent the page from entering the bfcache.
await event.viewTransition.finished;
heading.style.viewTransitionName = '';
}
}
});
En İyi Uygulamalar
- Mümkün olduğunda CSS aracılığıyla
view-transition-nameatayın. (DO) Adın gezinme bağlamına bağlı olduğu durumlarda JavaScript atamasını (pagerevealaracılığıyla) kullanın. - Oluşturmayı engelleyen komut dosyalarını küçük ve hızlı tutun (DO). Tarayıcıda yerleşik bir zaman aşımı (yaklaşık 4 saniye) vardır. Bu sürenin ardından geçiş tamamen atlanır (geçiş başlatıldıysa
viewTransition.ready,InvalidStateErrorile reddedilir). - Sayfanın derinliklerinde bulunan ve ilk görüntü alanında görünmeyen öğeleri engellemek için
<link rel="expect">KULLANMAYIN. Bu durum, görsel bir avantaj sağlamadan geçişi geciktirir. - İŞARETLEMEYİN: Analiz, reklam ağı, etiket yöneticisi veya diğer üçüncü taraf yükleyicileri, ilk görüntü alanına içerik ekleseler bile
blocking="render"ile işaretlemeyin. Ağ gecikmeleri, geçiş zaman aşımına dahil edilir ve çıkışları sayfanın kararlı durumunun bir parçası değildir. - Aynı sayfadaki birden fazla öğeye aynı
view-transition-namedeğerini ATAMAYIN. Yinelenen adlar, geçişin tamamının atlanmasına neden olur. - Yardımcı Teknoloji Zamanlama Etkisi:
blocking="render"kullanmak görsel güncellemeleri ve ilk boyamayı geciktirir. Bu durum, gören kullanıcılar için görsel hataları önlese de ekran okuyucular ve oluşturulan erişilebilirlik ağaçlarına bağlı diğer yardımcı teknolojiler için işleme gecikmesine veya ertelenen başlatmaya neden olabilir. Görsel süreklilik avantajlarını, görsel olmayan kullanıcılar için ilk okuma gecikmesine karşı değerlendirin ve oluşturmayı engelleyen komut dosyalarının minimum düzeyde ve son derece optimize edilmiş olduğundan emin olun.
Yedek Stratejiler
Belgeler arası görüntüleme geçişleri, progresif geliştirme için mükemmel bir adaydır. Bu kuralı desteklemeyen tarayıcılarda @view-transition kuralı yoksayılır ve standart aynı kaynak gezinmeleri, özellik olmadan gerçekleşeceği şekilde gerçekleşir. Destekleyen tarayıcılar sorunsuz geçişler sunarken diğerleri standart gezinme deneyimi sunar. Sınırlı tarayıcı desteği, bu özelliği kullanmaktan kaçınmak için bir neden değildir.
Belgeler arası görünüm geçişlerini destekleyen tüm tarayıcılar blocking="render" ve <link rel="expect">'yi de destekler. Bu nedenle, bu kılavuzda açıklanan oluşturmayı engelleyen özellikler için ayrı bir yedek gerekmez.
Dikkat edilmesi gereken diğer noktalar
- Performansa etkisi: Oluşturmayı engelleyen her kaynak, görünüm geçişi animasyonunun başlamasını geciktirir. Oluşturmayı engelleyen komut dosyalarının sayısını en aza indirin ve
<link rel="expect">öğesini yalnızca ekranın üst kısmındaki öğeler için kullanın. Yükleme gecikmelerini tamamen ortadan kaldırmak için Speculation Rules API'yi kullanarak hedef sayfaları önceden işleyin. - Zaman Aşımı Davranışı: Oluşturmayı engelleyen toplam süre yaklaşık 4 saniyeyi aşarsa tarayıcı geçişi atlar (ve etkin
viewTransition.readyvaatleriInvalidStateErrorile reddeder). Kritik kaynakların bu süre içinde yüklendiğinden emin olun. - Geri-ileri önbellek uyumluluğu: Geçişten sonra temizlenmeyen geçici
view-transition-nameatamaları, sayfanın geri-ileri önbelleğe girmesini engelleyebilir. Dinamik olarak atanan adları her zamanfinishedgeri çağırma işlevinde kaldırın.