İki farklı doküman arasında bir görüntüleme geçişi gerçekleştiğinde, buna dokümanlar arası görünüm geçişi adı verilir. Bu durum genellikle çok sayfalı uygulamalarda (MPA) geçerlidir. Dokümanlar arası görünüm geçişleri, Chrome 126 sürümünden itibaren Chrome'da desteklenmektedir.
Dokümanlar arası görünüm geçişleri, aynı doküman görünümü geçişleriyle aynı yapı taşlarını ve ilkeleri temel alır. Bu geçişler özellikle bilinçlidir:
- Tarayıcı, hem eski hem de yeni sayfada benzersiz bir
view-transition-name
öğesine sahip öğelerin anlık görüntülerini alır. - Oluşturma işlemi engellenirken DOM güncellenir.
- Son olarak, geçişler CSS animasyonlarıyla desteklenir.
Aynı doküman görüntüleme geçişlerine kıyasla farklı olan şey, dokümanlar arası görünüm geçişlerinde bir görüntüleme geçişi başlatmak için document.startViewTransition
yöntemini çağırmanızın gerekmemesidir. Bunun yerine, dokümanlar arası görünüm geçişinin tetikleyicisi, genellikle web sitenizin kullanıcısının bir bağlantıyı tıklayarak gerçekleştirdiği bir işlem olan, bir sayfadan diğerine aynı kaynaktan gitme işlemidir.
Diğer bir deyişle, iki doküman arasında bir görünüm geçişi başlatmak için çağrılacak bir API yoktur. Ancak yerine getirilmesi gereken iki koşul vardır:
- Her iki doküman da aynı kaynakta bulunmalıdır.
- Görüntüleme geçişine izin verilmesi için her iki sayfanın da etkinleştirilmesi gerekir.
Her iki koşul da bu dokümanın ilerleyen kısımlarında açıklanmaktadır.
Dokümanlar arası görünüm geçişleri, aynı kaynakta gezinmelerle sınırlıdır
Dokümanlar arası görünüm geçişleri yalnızca aynı kaynak gezinmeleriyle sınırlıdır. Her iki katılımcı sayfanın kaynağı aynıysa gezinmenin aynı kaynak olduğu kabul edilir.
Bir sayfanın kaynağı, web.dev sayfasında ayrıntılı olarak açıklandığı gibi, kullanılan şema, ana makine adı ve bağlantı noktasının bir kombinasyonudur.
![Şema, ana makine adı ve bağlantı noktasının vurgulandığı örnek URL. Tüm bunlar bir araya geldiğinde başlangıç noktasını oluşturur.](https://developer.chrome.com/static/docs/web-platform/view-transitions/image/origin.png?authuser=5&hl=tr)
Örneğin, kaynaklar aynı kaynak olduğundan developer.chrome.com
konumundan developer.chrome.com/blog
konumuna giderken dokümanlar arası görünüm geçişi yapabilirsiniz.
developer.chrome.com
sitesinden www.chrome.com
sitesine giderken çapraz kaynak ve aynı site olduğundan bu geçiş işlemini gerçekleştiremezsiniz.
Dokümanlar arası görünüm geçişleri etkindir
İki doküman arasında dokümanlar arası görünüm geçişi sağlamak için, katılımcı sayfaların her ikisinde de buna izin verilmiş olması gerekir. Bu işlem, CSS'deki @view-transition
kuyruklu a kuralı ile yapılır.
Dokümanlar arası, aynı kaynağa sahip gezinmelerde görünüm geçişlerini etkinleştirmek için @view-transition
kuralında navigation
açıklayıcıyı auto
olarak ayarlayın.
@view-transition {
navigation: auto;
}
navigation
tanımlayıcısını auto
olarak ayarlayarak aşağıdaki NavigationType için görünüm geçişlerinin yapılmasına izin vermiş olursunuz:
traverse
- Etkinleştirme, kullanıcı tarafından tarayıcı kullanıcı arayüzü mekanizmaları aracılığıyla başlatılmadıysa
push
veyareplace
.
auto
kapsamının dışında kalan gezinmeler, örneğin URL adres çubuğunu kullanarak gezinme veya bir yer işaretini tıklama gibi kullanıcı veya komut dosyası tarafından başlatılan yeniden yükleme biçimlerini kapsar.
Chrome'da gezinme işlemi çok uzun sürerse (Chrome'da dört saniyeden uzun sürerse) TimeoutError
DOMException
ile görüntüleme geçişi atlanır.
Dokümanlar arası görünüm geçişleri demosu
Stack Navigator demosu oluşturmak için görünüm geçişlerinin kullanıldığı aşağıdaki demoya göz atın. Burada document.startViewTransition()
için çağrı yok, görünüm geçişleri bir sayfadan diğerine gidilerek tetiklenir.
Dokümanlar arası görünüm geçişlerini özelleştirme
Dokümanlar arası görünüm geçişlerini özelleştirmek için kullanabileceğiniz bazı web platformu özellikleri vardır.
Bu özellikler, View Transition API spesifikasyonunun bir parçası değildir ancak onunla birlikte kullanılmak üzere tasarlanmıştır.
pageswap
ve pagereveal
etkinlikleri
Dokümanlar arası görünüm geçişlerini özelleştirmenize olanak tanımak için HTML spesifikasyonu, kullanabileceğiniz iki yeni etkinlik içerir: pageswap
ve pagereveal
.
Görünüm geçişinin gerçekleşip gerçekleşmemesine bakılmaksızın, aynı kaynaklar arasında yapılan her gezinme işleminde bu iki etkinlik tetiklenir. İki sayfa arasında bir görünüm geçişi gerçekleşmek üzereyse bu etkinliklerde viewTransition
özelliğini kullanarak ViewTransition
nesnesine erişebilirsiniz.
pageswap
etkinliği, sayfanın son karesi oluşturulmadan önce tetiklenir. Eski anlık görüntüler alınmadan hemen önce, giden sayfada bazı son dakika değişiklikleri yapmak için bunu kullanabilirsiniz.pagereveal
etkinliği başlatıldıktan veya yeniden etkinleştirildikten sonra, ancak ilk oluşturma fırsatından önce sayfada tetiklenir. Bunu kullanarak, yeni anlık görüntüler alınmadan önce yeni sayfayı özelleştirebilirsiniz.
Örneğin, bazı view-transition-name
değerlerini hızlı bir şekilde ayarlamak veya değiştirmek ya da bir dokümandan diğerine veri aktarmak için bu etkinlikleri kullanabilirsiniz. Bunu yapmak için sessionStorage
ürününden veri yazıp okuyarak görünüm geçişini gerçekte çalıştırmadan önce özelleştirebilirsiniz.
let lastClickX, lastClickY;
document.addEventListener('click', (event) => {
if (event.target.tagName.toLowerCase() === 'a') return;
lastClickX = event.clientX;
lastClickY = event.clientY;
});
// Write position to storage on old page
window.addEventListener('pageswap', (event) => {
if (event.viewTransition && lastClick) {
sessionStorage.setItem('lastClickX', lastClickX);
sessionStorage.setItem('lastClickY', lastClickY);
}
});
// Read position from storage on new page
window.addEventListener('pagereveal', (event) => {
if (event.viewTransition) {
lastClickX = sessionStorage.getItem('lastClickX');
lastClickY = sessionStorage.getItem('lastClickY');
}
});
İsterseniz, her iki etkinlikte de geçişi atlamaya karar verebilirsiniz.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
if (goodReasonToSkipTheViewTransition()) {
e.viewTransition.skipTransition();
}
}
}
pageswap
ve pagereveal
içindeki ViewTransition
nesnesi iki farklı nesne. Çeşitli vaatleri de farklı şekilde ele alırlar:
pageswap
: Doküman gizlendikten sonra eskiViewTransition
nesnesi atlanır. Böyle bir durumdaviewTransition.ready
reddeder veviewTransition.finished
çözümlenir.pagereveal
:updateCallBack
sözü bu noktada zaten tamamlanmıştır.viewTransition.ready
veviewTransition.finished
taahhütlerini kullanabilirsiniz.
Navigasyon etkinleştirme bilgileri
Hem pageswap
hem de pagereveal
etkinliklerinde, eski ve yeni sayfaların URL'lerine göre de işlem yapabilirsiniz.
Örneğin, MPA Yığın Gezgini'nde kullanılacak animasyon türü gezinme yoluna bağlıdır:
- Genel bakış sayfasından ayrıntılar sayfasına gidildiğinde yeni içeriğin sağdan sola doğru kaydırılması gerekir.
- Ayrıntılar sayfasından genel bakış sayfasına geçildiğinde eski içeriğin soldan sağa doğru kayması gerekir.
Bunu yapmak için, pageswap
örneğinde gerçekleşmek üzere olan veya az önce gerçekleşen pagereveal
örneğinde gezinmeyle ilgili bilgilere ihtiyacınız vardır.
Bunun için tarayıcılar, aynı kaynakta gezinmeyle ilgili bilgileri barındıran NavigationActivation
nesnelerini artık gösterebilir. Bu nesne, Gezinme API'sindeki navigation.entries()
bölümünde bulunan gezinme türünü, geçerli ve son hedef geçmişi girişlerini gösterir.
Etkinleştirilmiş bir sayfada, bu nesneye navigation.activation
üzerinden erişebilirsiniz. pageswap
etkinliğinde, buna e.activation
üzerinden erişebilirsiniz.
Görünüm geçişine katılması gereken öğelerde view-transition-name
değerlerini ayarlamak için pageswap
ve pagereveal
etkinliklerinde NavigationActivation
bilgilerini kullanan bu Profiller demosuna göz atın.
Böylece listedeki her öğeyi önceden view-transition-name
ile dekore etmeniz gerekmez. Bunun yerine bu, JavaScript kullanılarak tam zamanında ve yalnızca gereken öğelerde gerçekleşir.
Bu kod aşağıdaki gibidir:
// OLD PAGE LOGIC
window.addEventListener('pageswap', async (e) => {
if (e.viewTransition) {
const targetUrl = new URL(e.activation.entry.url);
// Navigating to a profile page
if (isProfilePage(targetUrl)) {
const profile = extractProfileNameFromUrl(targetUrl);
// Set view-transition-name values on the clicked row
document.querySelector(`#${profile} span`).style.viewTransitionName = 'name';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'avatar';
// Remove view-transition-names after snapshots have been taken
// (this to deal with BFCache)
await e.viewTransition.finished;
document.querySelector(`#${profile} span`).style.viewTransitionName = 'none';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'none';
}
}
});
// NEW PAGE LOGIC
window.addEventListener('pagereveal', async (e) => {
if (e.viewTransition) {
const fromURL = new URL(navigation.activation.from.url);
const currentURL = new URL(navigation.activation.entry.url);
// Navigating from a profile page back to the homepage
if (isProfilePage(fromURL) && isHomePage(currentURL)) {
const profile = extractProfileNameFromUrl(currentURL);
// Set view-transition-name values on the elements in the list
document.querySelector(`#${profile} span`).style.viewTransitionName = 'name';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'avatar';
// Remove names after snapshots have been taken
// so that we're ready for the next navigation
await e.viewTransition.ready;
document.querySelector(`#${profile} span`).style.viewTransitionName = 'none';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'none';
}
}
});
Ayrıca kod, görüntüleme geçişi çalıştırıldıktan sonra view-transition-name
değerlerini kaldırarak kendiliğinden temizlenir. Bu şekilde, sayfa art arda yapılan gezinmeler için hazır olur ve geçmiş geçişini de işleyebilir.
Buna yardımcı olmak için geçici olarak view-transition-name
değerini ayarlayan bu yardımcı program işlevini kullanın.
const setTemporaryViewTransitionNames = async (entries, vtPromise) => {
for (const [$el, name] of entries) {
$el.style.viewTransitionName = name;
}
await vtPromise;
for (const [$el, name] of entries) {
$el.style.viewTransitionName = '';
}
}
Önceki kod artık aşağıdaki gibi basitleştirilebilir:
// OLD PAGE LOGIC
window.addEventListener('pageswap', async (e) => {
if (e.viewTransition) {
const targetUrl = new URL(e.activation.entry.url);
// Navigating to a profile page
if (isProfilePage(targetUrl)) {
const profile = extractProfileNameFromUrl(targetUrl);
// Set view-transition-name values on the clicked row
// Clean up after the page got replaced
setTemporaryViewTransitionNames([
[document.querySelector(`#${profile} span`), 'name'],
[document.querySelector(`#${profile} img`), 'avatar'],
], e.viewTransition.finished);
}
}
});
// NEW PAGE LOGIC
window.addEventListener('pagereveal', async (e) => {
if (e.viewTransition) {
const fromURL = new URL(navigation.activation.from.url);
const currentURL = new URL(navigation.activation.entry.url);
// Navigating from a profile page back to the homepage
if (isProfilePage(fromURL) && isHomePage(currentURL)) {
const profile = extractProfileNameFromUrl(currentURL);
// Set view-transition-name values on the elements in the list
// Clean up after the snapshots have been taken
setTemporaryViewTransitionNames([
[document.querySelector(`#${profile} span`), 'name'],
[document.querySelector(`#${profile} img`), 'avatar'],
], e.viewTransition.ready);
}
}
});
Oluşturma engelleme ile içeriğin yüklenmesini bekleyin
Bazı durumlarda, yeni DOM'de belirli bir öğe mevcut olana kadar sayfanın ilk oluşturulmasını bekletmek isteyebilirsiniz. Bu şekilde yanıp sönmeyi önleyerek, canlandırmak istediğiniz durumun kararlı olmasını sağlarsınız.
<head>
içinde, aşağıdaki meta etiketi kullanarak sayfanın ilk oluşturulmasından önce bulunması gereken bir veya daha fazla öğe kimliği tanımlayın.
<link rel="expect" blocking="render" href="#section1">
Bu meta etiket, içeriğin yüklenmesi değil, öğenin DOM'da olması gerektiği anlamına gelir. Örneğin resimlerde, DOM ağacında belirtilen id
ile <img>
etiketinin sadece varlığı, koşulun doğru olarak değerlendirilmesi için yeterlidir. Resim hâlâ yükleniyor olabilir.
Oluşturma engellemeye başlamadan önce, artımlı oluşturmanın Web'in temel bir özelliği olduğunu unutmayın. Bu nedenle, oluşturmayı engellemeyi seçerken dikkatli olun. Oluşturmayı engellemenin etkisi her durum için ayrı ayrı değerlendirilmelidir. Varsayılan olarak, blocking=render
ürününün kullanıcılarınız üzerindeki etkisini etkin bir şekilde ölçemiyorsanız ve Core Web Vitals üzerindeki etkisini ölçemiyorsanız kullanmaktan kaçının.
Dokümanlar arası görünüm geçişlerindeki geçiş türlerini görüntüleme
Dokümanlar arası görünüm geçişleri, animasyonları ve hangi öğelerin yakalanacağını özelleştirmek için görünüm geçiş türlerini de destekler.
Örneğin, bir sayfada sonraki veya önceki sayfaya giderken sıralamadan daha üst veya daha alt bir sayfaya mı gittiğinize bağlı olarak farklı animasyonlar kullanmak isteyebilirsiniz.
Bu türleri önceden ayarlamak için türleri @view-transition
kuralına ekleyin:
@view-transition {
navigation: auto;
types: slide, forwards;
}
Türleri hemen ayarlamak için pageswap
ve pagereveal
etkinliklerini kullanarak e.viewTransition.types
değerini değiştirin.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
const transitionType = determineTransitionType(navigation.activation.from, navigation.activation.entry);
e.viewTransition.types.add(transitionType);
}
});
Türler, eski sayfadaki ViewTransition
nesnesinden yeni sayfanın ViewTransition
nesnesine otomatik olarak taşınmaz. Animasyonların beklendiği gibi çalışması için en azından yeni sayfada kullanılacak türleri belirlemeniz gerekir.
Bu türlere yanıt vermek için :active-view-transition-type()
sanal sınıf seçiciyi aynı doküman görüntüleme geçişleriyle aynı şekilde kullanın.
/* Determine what gets captured when the type is forwards or backwards */
html:active-view-transition-type(forwards, backwards) {
:root {
view-transition-name: none;
}
article {
view-transition-name: content;
}
.pagination {
view-transition-name: pagination;
}
}
/* Animation styles for forwards type only */
html:active-view-transition-type(forwards) {
&::view-transition-old(content) {
animation-name: slide-out-to-left;
}
&::view-transition-new(content) {
animation-name: slide-in-from-right;
}
}
/* Animation styles for backwards type only */
html:active-view-transition-type(backwards) {
&::view-transition-old(content) {
animation-name: slide-out-to-right;
}
&::view-transition-new(content) {
animation-name: slide-in-from-left;
}
}
/* Animation styles for reload type only */
html:active-view-transition-type(reload) {
&::view-transition-old(root) {
animation-name: fade-out, scale-down;
}
&::view-transition-new(root) {
animation-delay: 0.25s;
animation-name: fade-in, scale-up;
}
}
Türler yalnızca bir aktif görüntüleme geçişi için geçerli olduğundan, görünüm geçişi tamamlandığında türler otomatik olarak temizlenir. Bu nedenle, türler BFCache gibi özelliklerle iyi performans gösterir.
Demo
Aşağıdaki sayfalara ayırma demosunda, sayfa içerikleri, gittiğiniz sayfa numarasına göre ileriye veya geriye doğru kaydırılır.
Kullanılacak geçiş türü, pagereveal
ve pageswap
etkinliklerinde gelen ve giden URL'lere bakılarak belirlenir.
const determineTransitionType = (fromNavigationEntry, toNavigationEntry) => {
const currentURL = new URL(fromNavigationEntry.url);
const destinationURL = new URL(toNavigationEntry.url);
const currentPathname = currentURL.pathname;
const destinationPathname = destinationURL.pathname;
if (currentPathname === destinationPathname) {
return "reload";
} else {
const currentPageIndex = extractPageIndexFromPath(currentPathname);
const destinationPageIndex = extractPageIndexFromPath(destinationPathname);
if (currentPageIndex > destinationPageIndex) {
return 'backwards';
}
if (currentPageIndex < destinationPageIndex) {
return 'forwards';
}
return 'unknown';
}
};
Geri bildirim
Geliştiricilerin geri bildirimleri her zaman çok değerlidir. Paylaşmak için GitHub'da CSS Çalışma Grubu'na sorun bildiriminde bulunun, öneriler ve sorular sorun. Sorununuzun önüne [css-view-transitions]
ekleyin.
Bir hatayla karşılaşırsanız bunun yerine Chromium hatası bildiriminde bulunun.