1. Başlamadan önce
Bu codelab'de, Google Chrome'un yerel olarak desteklediği en yeni API'lerle örnek bir web uygulamasına anında gezinme ve sorunsuz sayfa geçişleri eklemeyi öğreneceksiniz.
Örnek web uygulaması, popüler meyve ve sebzelerin besin değerlerini kontrol eder. Meyve listesi ve meyve ayrıntıları sayfaları tek sayfalık uygulama (SPA) olarak, sebze listesi ve sebze ayrıntıları sayfaları ise geleneksel çok sayfalı uygulama (MPA) olarak oluşturulur.

Özellikle anında gezinme için önceden işleme, geri-ileri önbellek (bfcache) ve Private Prefetch Proxy'yi, sorunsuz sayfa geçişleri için ise kök/paylaşılan öğe geçişlerini uyguluyorsunuz. Çok sayfalı uygulama sayfaları için önceden işleme ve geri-ileri önbellek, tek sayfalı uygulama sayfaları için ise paylaşılan öğe geçişleri uygularsınız.
Site hızı, kullanıcı deneyiminin her zaman önemli bir yönü olmuştur. Bu nedenle Google, gerçek dünyadaki kullanıcı deneyimini ölçmek için web sayfalarının yükleme performansını, etkileşimini ve görsel kararlılığını ölçen bir metrik grubu olan Core Web Vitals'ı kullanıma sundu. En yeni API'ler, web sitenizin alandaki Core Web Vitals puanını (özellikle yükleme performansı için) iyileştirmenize yardımcı olur.

Mindvalley'den demo
Kullanıcılar, mobil uygulamalarda gezinme ve durum değişikliklerini son derece sezgisel hale getirmek için geçişlerin kullanımına da alışkındır. Maalesef bu tür kullanıcı deneyimlerinin web'de kopyalanması kolay değildir. Mevcut web platformu API'leriyle benzer efektler elde edebilirsiniz ancak özellikle Android veya iOS uygulamalarındaki benzer özelliklerle karşılaştırıldığında geliştirme süreci çok zor veya karmaşık olabilir. Sorunsuz API'ler, uygulama ve web arasındaki bu kullanıcı ve geliştirici deneyimi boşluğunu doldurmak için tasarlanmıştır.

pixiv ve Tokopedia'dan demolar
Ön koşullar
Aşağıdakiler hakkında bilgi sahibi olunmalıdır:
- HTML
- CSS
- JavaScript
- Google Chrome Geliştirici Araçları
Öğrenecekleriniz:
Nasıl uygulanır?
- Önceden işleme
- bfcache
- Private Prefetch Proxy
- Kök/paylaşılan öğe geçişleri
Ne oluşturacaksınız?
En yeni anlık ve sorunsuz tarayıcı özellikleriyle zenginleştirilmiş, Next.js ile oluşturulmuş örnek bir web uygulaması:
- Önceden oluşturma ile neredeyse anında gezinme
- Tarayıcının geri ve ileri düğmeleriyle anında yükleme için bfcache
- Private Prefetch Proxy veya imzalı takas (SXG) ile kaynaklar arası gezinmede mükemmel ilk izlenimler
- Kök/paylaşılan öğe geçişiyle sayfalar arasında sorunsuz geçiş
İhtiyacınız olanlar
- Chrome 101 veya sonraki sürümler
2. Başlayın
Chrome flag'lerini etkinleştirme
- about://flags adresine gidin ve
Prerender2iledocumentTransition APIçalışma zamanı işaretlerini etkinleştirin. - Tarayıcınızı yeniden başlatın.
Kodu alın
- Bu GitHub deposundaki kodu en sevdiğiniz geliştirme ortamında açın:
git clone -b codelab git@github.com:googlechromelabs/instant-seamless-demo.git
- Sunucuyu çalıştırmak için gereken bağımlılıkları yükleyin:
npm install
- Sunucuyu 3000 numaralı bağlantı noktasında başlatın:
npm run dev
- Tarayıcınızda http://localhost:3000 adresine gidin.
Artık uygulamanızı düzenleyip iyileştirebilirsiniz. Değişiklik yaptığınızda uygulama yeniden yüklenir ve değişiklikleriniz doğrudan görünür.
3. Önceden işleme özelliğini entegre etme
Bu demoda, örnek uygulamadaki sebze ayrıntıları sayfasının yüklenme süresi, sunucu tarafındaki rastgele bir gecikme nedeniyle çok yavaştır. Önceden oluşturma ile bu bekleme süresini ortadan kaldırabilirsiniz.
Sebze listesi sayfasına önceden oluşturma düğmeleri eklemek ve kullanıcının tıklamasının ardından önceden oluşturma işlemini tetiklemelerine izin vermek için:
- speculation-rules komut dosyası etiketini dinamik olarak ekleyen bir düğme bileşeni oluşturun:
components/prerender-button.js
import { useContext } from 'react'
import ResourceContext from './resource-context'
// You use resource context to manage global states.
// In the PrerenderButton component, you update the prerenderURL parameter when the button is clicked.
export default function PrerenderButton() {
const { dispatch } = useContext(ResourceContext)
const handleClick = (e) => {
e.preventDefault()
e.stopPropagation()
const parent = e.target.closest('a')
if (!parent) {
return
}
const href = parent.getAttribute('href')
dispatch({ type: 'update', prerenderURL: href })
}
return (
<button className='ml-auto bg-gray-200 hover:bg-gray-300 px-4 rounded' onClick={handleClick}>
Prerender
</button>
)
}
PrerenderButtonbileşeninilist-item.jsdosyasında içe aktarın.
components/list-item.js
// Codelab: Add a PrerenderButton component.
import PrerenderButton from './prerender-button'
...
function ListItemForMPA({ item, href }) {
return (
<a href={href} className='block flex items-center'>
<Icon src={item.image} />
<div className='text-xl'>{item.name}</div>
{/* Codelab: Add PrerenderButton component. */}
<PrerenderButton />
</a>
)
}
- Spekülasyon Kuralları API'si eklemek için bir bileşen oluşturun.
SpeculationRules bileşeni, uygulama prerenderURL durumunu güncellediğinde sayfaya dinamik olarak bir komut dosyası etiketi ekler.
components/speculationrules.js
import Script from 'next/script'
import { useContext, useMemo } from 'react'
import ResourceContext from './resource-context'
export default function SpeculationRules() {
const { state } = useContext(ResourceContext)
const { prerenderURL } = state
return useMemo(() => {
return (
<>
{prerenderURL && (
<Script id='speculationrules' type='speculationrules'>
{`
{
"prerender":[
{
"source": "list",
"urls": ["${prerenderURL}"]
}
]
}
`}
</Script>
)}
</>
)
}, [prerenderURL])
}
- Bileşenleri uygulamayla entegre edin.
pages/_app.js
// Codelab: Add the SpeculationRules component.
import SpeculationRules from '../components/speculationrules'
function MyApp({ Component, pageProps }) {
useAnalyticsForSPA()
return (
<ResourceContextProvider>
<Layout>
<Component {...pageProps} />
</Layout>
{/* Codelab: Add SpeculationRules component */}
<SpeculationRules />
<Script id='analytics-for-mpa' strategy='beforeInteractive' src='/analytics.js' />
</ResourceContextProvider>
)
}
export default MyApp
- Önceden oluştur'u tıklayın.
Artık yükleme hızında önemli bir iyileşme olduğunu görebilirsiniz. Gerçek kullanım alanında, önceden oluşturma, kullanıcının bir sonraki ziyaret etme olasılığı olan sayfa için bazı sezgisel yöntemlerle tetiklenir.

Analytics
Varsayılan olarak, örnek web uygulamasındaki analytics.js dosyası, DOMContentLoaded etkinliği gerçekleştiğinde bir sayfa görüntüleme etkinliği gönderir. Maalesef bu etkinlik, önceden oluşturma aşamasında tetiklendiği için bu yaklaşım uygun değildir.
Bu sorunu düzeltmek için document.prerendering ve prerenderingchange etkinliğini kullanıma sunuyoruz:
analytics.jsdosyasını yeniden yazın:
public/analytics.js
const sendEvent = (type = 'pageview') => {
// Codelab: Make analytics prerendering compatible.
// The pageshow event could happen in the prerendered page before activation.
// The prerendered page should be handled by the prerenderingchange event.
if (document.prerendering) {
return
}
console.log(`Send ${type} event for MPA navigation.`)
fetch(`/api/analytics?from=${encodeURIComponent(location.pathname)}&type=${type}`)
}
...
// Codelab: Make analytics prerendering compatible.
// The prerenderingchange event is triggered when the page is activated.
document.addEventListener('prerenderingchange', () => {
console.log('The prerendered page was activated.')
sendEvent()
})
...
Harika! Analizlerinizi önceden oluşturma ile uyumlu olacak şekilde başarıyla değiştirdiniz. Artık tarayıcı konsolunda sayfa görüntüleme günlüklerini doğru zamanlamayla görebilirsiniz.
4. bfcache engelleyicilerini kaldırma
unload etkinlik işleyicisini kaldırma
Gereksiz bir unload etkinliğinin olması, artık önerilmeyen çok yaygın bir hatadır. Bu durum, geri-ileri önbelleğin çalışmasını engellemekle kalmaz, aynı zamanda güvenilir de değildir. Örneğin, mobil cihazlarda ve Safari'de her zaman tetiklenmez.
unload etkinliği yerine, unload etkinliği tetiklendiğinde ve bir sayfa geri-ileri önbelleğe yerleştirildiğinde tüm durumlarda tetiklenen pagehide etkinliğini kullanırsınız.
unload etkinlik işleyicisini kaldırmak için:
analytics.jsdosyasında,unloadetkinlik işleyicisinin kodunupagehideetkinlik işleyicisinin koduyla değiştirin:
public/analytics.js
// Codelab: Remove the unload event handler for bfcache.
// The unload event handler prevents the content from being stored in bfcache. Use the pagehide event instead.
window.addEventListener('pagehide', () => {
sendEvent('leave')
})
Önbellek kontrolü üst bilgisini güncelleme
Cache-control: no-store HTTP üstbilgisiyle sunulan sayfalar, tarayıcının bfcache özelliğinden yararlanmaz. Bu nedenle, bu üstbilgiyi dikkatli kullanmak iyi bir uygulamadır. Özellikle sayfa, oturum açma durumu gibi kişiselleştirilmiş veya kritik bilgiler içermiyorsa büyük olasılıkla Cache-control: no-store HTTP üstbilgisiyle sunmanız gerekmez.
Örnek uygulamanın önbellek kontrolü üstbilgisini güncellemek için:
getServerSidePropskodunu değiştirin:
pages/vegetables/index.js
export const getServerSideProps = middleware(async (ctx) => {
const { req, res } = ctx
// Codelab: Modify the cache-control header.
res.setHeader('Cache-Control', 'public, s-maxage=10, stale-while-revalidate=59')
...
pages/vegetables/[name].js
export const getServerSideProps = middleware(async (ctx) => {
const { req, res, query } = ctx
// Codelab: Modify the cache-control header.
res.setHeader('Cache-Control', 'public, s-maxage=10, stale-while-revalidate=59')
...
Bir sayfanın bfcache'ten geri yüklenip yüklenmediğini belirleme
pageshow etkinliği, sayfa ilk yüklendiğinde ve sayfa geri-ileri önbellekten her geri yüklendiğinde load etkinliğinden hemen sonra tetiklenir. pageshow etkinliğinde, sayfa bfcache'ten geri yüklenmişse doğru, yüklenmemişse yanlış olan bir persisted özelliği bulunur. Normal sayfa yüklemelerini geri/ileri önbellek geri yüklemelerinden ayırt etmek için persisted özelliğini kullanabilirsiniz. Başlıca analiz hizmetleri bfcache'i tanımalıdır ancak sayfanın bfcache'ten geri yüklenip yüklenmediğini kontrol edebilir ve etkinlikleri manuel olarak gönderebilirsiniz.
Bir sayfanın bfcache'ten geri yüklenip yüklenmediğini belirlemek için:
- Bu kodu
analytics.jsdosyasına ekleyin.
public/analytics.js
// Codelab: Use the pageshow event handler for bfcache.
window.addEventListener('pageshow', (e) => {
// If the persisted flag exists, the page was restored from bfcache.
if (e.persisted) {
console.log('The page was restored from bfcache.')
sendEvent()
}
})
Web sayfasında hata ayıklama
Chrome Geliştirici Araçları, sayfalarınızın bfcache için optimize edildiğinden emin olmak üzere test etmenize ve uygun olmamalarına neden olabilecek sorunları belirlemenize yardımcı olabilir.
Belirli bir sayfayı test etmek için:
- Chrome'da sayfaya gidin.
- Chrome Geliştirici Araçları'nda Uygulama > Geri/İleri Önbelleği > Testi Çalıştır'ı tıklayın.
Chrome Geliştirici Araçları, sayfanın geri-ileri önbellekten geri yüklenip yüklenemeyeceğini belirlemek için sayfadan ayrılmaya ve ardından geri dönmeye çalışır.

Başarılı olursa panelde sayfanın geri-ileri önbellekten geri yüklendiği belirtilir:

Başarısız olursa panelde sayfanın geri yüklenmediği ve bunun nedeni belirtilir. Nedeni geliştirici olarak ele alabileceğiniz bir durumsa panelde bu da belirtilir.

5. Siteler arası önceden getirmeyi etkinleştirme
Önceden getirme, kullanıcı gezinirken baytların tarayıcıda hazır olması için getirme işlemlerini erken başlatır. Bu da gezinmeyi hızlandırır. Bu, Core Web Vitals'ı iyileştirmenin ve gezinmeden önce bazı ağ etkinliklerini telafi etmenin kolay bir yoludur. Bu, Largest Contentful Paint (LCP) değerini doğrudan hızlandırır ve gezinme sırasında First Input Delay (FID) ile Cumulative Layout Shift (CLS) için daha fazla alan sağlar.
Private Prefetch Proxy, siteler arası önceden getirme özelliğini etkinleştirir ancak kullanıcıyla ilgili özel bilgileri hedef sunucuya göstermez.

Private Prefetch Proxy ile siteler arası önceden getirmeyi etkinleştirme
Web sitesi sahipleri, önceden getirme işlemini traffic-advice adlı iyi bilinen bir kaynak aracılığıyla kontrol eder. Bu kaynak, web tarayıcıları için /robots.txt'ye benzer ve bir HTTP sunucusunun, uygulayan aracıların ilgili tavsiyeyi uygulamasını bildirmesine olanak tanır. Şu anda web sitesi sahipleri, ağ bağlantılarına izin verilmemesi veya bağlantıların sınırlandırılması konusunda aracıya tavsiyede bulunabilir. Gelecekte başka tavsiyeler de eklenebilir.
Trafik tavsiyesi kaynağı barındırmak için:
- Aşağıdaki JSON benzeri dosyayı ekleyin:
public/.well-known/traffic-advice
[
{
"user_agent": "prefetch-proxy",
"google_prefetch_proxy_eap": {
"fraction": 1
}
}
]
google_prefetch_proxy_eap alanı, erken erişim programı için özel bir alandır. fraction alanı ise Private Prefetch Proxy'nin gönderdiği istenen önceden getirmelerin oranını kontrol etmek için kullanılan bir alandır.
Trafik tavsiyesi, application/trafficadvice+json MIME türüyle döndürülmelidir.
next.config.jsdosyasında yanıt başlığını yapılandırın:
next.config.js
const nextConfig = {
// Codelab: Modify content-type for traffic advice file.
async headers() {
return [
{
source: '/.well-known/traffic-advice',
headers: [
{
key: 'Content-Type',
value: 'application/trafficadvice+json',
},
],
},
]
},
}
module.exports = nextConfig
6. Shared Element Transitions API'yi entegre etme
Kullanıcı web'de bir sayfadan diğerine gittiğinde, ilk sayfa kaybolup yeni sayfa göründüğü için gördüğü içerik aniden ve beklenmedik bir şekilde değişir. Bu sıralı ve bağlantısız kullanıcı deneyimi, kullanıcının bulunduğu yere nasıl geldiğini anlamaya çalışmak zorunda kalması nedeniyle kafa karıştırıcıdır ve daha yüksek bir bilişsel yüke yol açar. Ayrıca bu deneyim, kullanıcıların istenen hedefin yüklenmesini beklerken sayfa yüklemesini ne kadar algıladığını artırır.
Sayfalar arasında gezinirken bağlamda kalabildikleri için kullanıcıların bilişsel yükünü azaltan sorunsuz yükleme animasyonları, bu sırada ilgi çekici ve keyifli bir şey gördükleri için yükleme gecikmesini de azaltır. Bu nedenlerle çoğu platform, geliştiricilerin sorunsuz geçişler oluşturmasına olanak tanıyan, kullanımı kolay temel işlevler sağlar (ör. Android, iOS, macOS ve Windows).
Shared Element Transitions API, geçişlerin belgeler arası (MPA) veya belge içi (SPA) olmasına bakılmaksızın geliştiricilere web'de aynı özelliği sunar.

pixiv ve Tokopedia'dan demolar
Örnek uygulamanın SPA bölümü için paylaşılan öğe geçişleri API'sini entegre etmek üzere:
use-page-transition.jsdosyasındaki geçişi yönetmek için özel bir kanca oluşturun:
utils/use-page-transition.js
import { useEffect, useContext, useRef, useCallback } from 'react'
import ResourceContext from '../components/resource-context'
// Call this hook on this first page before you start the page transition. For Shared Element Transitions, you need to call the transition.start() method before the next page begins to render, and you need to do the Document Object Model (DOM) modification or setting of new shared elements inside the callback so that this hook returns the promise and defers to the callback resolve.
export const usePageTransitionPrep = () => {
const { dispatch } = useContext(ResourceContext)
return (elm) => {
const sharedElements = elm.querySelectorAll('.shared-element')
// Feature detection
if (!document.createDocumentTransition) {
return null
}
return new Promise((resolve) => {
const transition = document.createDocumentTransition()
Array.from(sharedElements).forEach((elm, idx) => {
transition.setElement(elm, `target-${idx}`)
})
transition.start(async () => {
resolve()
await new Promise((resolver) => {
dispatch({ type: 'update', transition: { transition, resolver } })
})
})
})
}
}
// Call this hook on the second page. Inside the useEffect hook, you can refer to the actual DOM element and set them as shared elements with the transition.setElement() method. When the resolver function is called, the transition is initiated between the captured images and newly set shared elements.
export const usePageTransition = () => {
const { state, dispatch } = useContext(ResourceContext)
const ref = useRef(null)
const setRef = useCallback((node) => {
ref.current = node
}, [])
useEffect(() => {
if (!state.transition || !ref.current) {
return
}
const { transition, resolver } = state.transition
const sharedElements = ref.current.querySelectorAll('.shared-element')
Array.from(sharedElements).forEach((elm, idx) => {
transition.setElement(elm, `target-${idx}`)
})
resolver()
return () => {
dispatch({ type: 'update', transition: null })
}
})
return setRef
}
- Liste sayfasında
usePageTransitionPrep()özel kancasını çağırın ve ardındanclicketkinliğindekitransition.start()yöntemini tetiklemek için asenkron işlevi çağırın.
İşlevin içinde, shared-element sınıf öğeleri toplanır ve paylaşılan öğeler olarak kaydedilir.
components/list-item.js
// Codelab: Add the Shared Element Transitions API.
import { usePageTransitionPrep } from '../utils/use-page-transition'
...
function ListItemForSPA({ item, href }) {
// Codelab: Add Shared Element Transitions.
const transitionNextState = usePageTransitionPrep()
const handleClick = async (e) => {
const elm = e.target.closest('a')
await transitionNextState(elm)
}
return (
<Link href={href}>
<a className='block flex items-center' onClick={handleClick}>
<Icon src={item.image} name={item.name} className='shared-element' />
<div className='text-xl'>{item.name}</div>
</a>
</Link>
)
}
- Ayrıntılar sayfasında,
transition.start()geri çağırma işlevini tamamlamak içinusePageTransition()kancasını çağırın.
Bu geri çağırmada, ayrıntılar sayfasındaki paylaşılan öğeler de kaydedilir.
pages/fruits/[name].js
// Codelab: Add the Shared Element Transitions API.
import { usePageTransition } from '../../utils/use-page-transition'
const Item = ({ data }) => {
const { name, image, amountPer, nutrition } = data
// Codelab: Add the Shared Element Transitions API.
const ref = usePageTransition()
return (
<div className={'flex flex-col items-center justify-center py-4 px-4 sm:flex-row'} ref={ref}>
<div className='flex flex-col items-center sm:w-2/4'>
<Image
className='object-cover border-gray-100 border-2 rounded-full shared-element'
src={image}
width='240'
height='240'
alt={`picture of ${name}`}
/>
<h1 className='text-4xl font-bold mt-4'>{name}</h1>
</div>
<div className='sm:w-2/4 w-full'>
<Nutrition amountPer={amountPer} nutrition={nutrition} />
</div>
</div>
)
...
}
Artık resim öğelerinin liste ve ayrıntı sayfalarında paylaşıldığını ve sayfa geçişinde sorunsuz bir şekilde bağlandığını görebilirsiniz. Hatta CSS sözde öğeleri ile animasyonu daha da süsleyebilirsiniz.

7. Tebrikler
Tebrikler! Düşük sürtünmeli, ilgi çekici ve sezgisel bir kullanıcı deneyimi sunan anlık ve sorunsuz bir web uygulaması oluşturdunuz.
Daha fazla bilgi
Önceden işleme
- Yenilenen önceden işleme
- Tahmine dayalı önceden işleme ile tarayıcıda anında sayfa yükleme
- quicklink
bfcache
Siteler arası önceden getirme
İmzalı takaslar
Kök/paylaşılan öğe geçişleri
Bu API'ler henüz geliştirmenin ilk aşamalarında olduğundan lütfen geri bildiriminizi crbug.com adresinden veya ilgili API'lerin GitHub deposundaki sorunlar bölümünden paylaşın.