Sayfa kayması (CLS) nasıl sıfırlanır?
Okumaya başladığınız paragraf aşağı kayıyor, tıklamak üzere olduğunuz buton yerinden oynuyor ve yanlış linke basıyorsunuz. CLS bu deneyimi ölçüyor. İyi haber şu: üç Core Web Vitals metriği içinde düzeltmesi en öngörülebilir olan CLS, çünkü sebeplerin neredeyse tamamı birkaç kalıba giriyor.
Hedef, gerçek kullanıcıların 75. yüzdeliğinde CLS değerinin 0,1 veya altında olması. Ben çoğu sitede sıfıra yakın bir değeri makul bir hedef olarak görüyorum.
CLS neyi sayar, neyi saymaz?
CLS (Cumulative Layout Shift), görünür alandaki elemanların beklenmedik şekilde yer değiştirmesini ölçer. Her kayma için bir puan hesaplanır: kayan alanın görünür alana oranı ile kayma mesafesinin çarpımı. Bu puanlar "oturum pencereleri" (session windows) halinde gruplanır: aralarında 1 saniyeden az boşluk olan ve toplam 5 saniyeyi geçmeyen kaymalar aynı pencereye girer. Sayfanın CLS değeri, en yüksek puanlı penceredir.
| CLS değeri | Değerlendirme |
|---|---|
| 0,1 ve altı | İyi |
| 0,1-0,25 | İyileştirme gerekli |
| 0,25 üstü | Kötü |
Hariç tutulan durumlar önemli:
- Kullanıcı girişinden sonraki 500 ms: Tıklama, dokunma veya tuş vuruşundan hemen sonra olan kaymalar beklenen kabul edilir. Akordeon açmak CLS üretmez.
- Kaydırma: Sayfayı kaydırmak bir kayma değildir; elemanlar birbirine göre yer değiştirmez.
transformile yapılan animasyonlar: Layout'u değiştirmediği için kayma sayılmaz.
Dikkat: "üzerine gelme" (hover) bir kullanıcı girişi sayılmaz. Hover ile açılıp içeriği iten bir menü CLS üretebilir.
En sık görülen sebepler
Boyutsuz görseller ve iframe'ler
Tarayıcı görselin boyutunu dosya inene kadar bilmiyorsa, ona sıfır yükseklik ayırır. Görsel inince alttaki her şey aşağı iter. YouTube gibi gömülü iframe'lerde de durum aynı.
Yer ayrılmamış reklamlar ve gömülü içerikler
Reklam alanı boş bir div olarak başlar, reklam gelince genişler. Reklamın boyutu değişken olabildiği için bu sorun sinsi: bazı gösterimlerde kayma olur, bazılarında olmaz.
Sonradan eklenen bantlar ve çerez bildirimleri
Sayfanın üstüne JavaScript ile eklenen kampanya bandı, "uygulamayı indir" çubuğu veya belge akışına eklenen çerez bildirimi tüm içeriği aşağı iter. Bu, sahada en çok gördüğüm sebep.
Web fontlarının değişmesi
Yedek font ile metin çizilir, web fontu inince yerine geçer. İki fontun genişlik ve satır yüksekliği farklıysa satır sayısı değişir ve paragraf altındaki her şey kayar.
Layout özelliklerini canlandırmak
top, left, height, margin gibi özellikleri canlandıran animasyonlar her karede layout'u değiştirir ve kayma üretebilir.
Çözümler
Görsel ve iframe'lere boyut vermek
En basit ve en etkili düzeltme: her <img> ve <iframe> için width ve height yazmak. Modern tarayıcılar bu iki değerden en-boy oranını hesaplar ve CSS'te genişlik esnek olsa bile doğru yüksekliği önceden ayırır.
<!-- Tarayıcı 16:9 oranını buradan hesaplar -->
<img src="/img/grafik.webp" width="1200" height="675" alt="Aylık tıklama grafiği">/* Görsel esnek genişlikte, oran korunur */
img { max-width: 100%; height: auto; }
/* Gömülü video için oran önceden ayrılır */
.video-kapsayici iframe { width: 100%; aspect-ratio: 16 / 9; height: auto; }Görsel optimizasyonunun diğer tarafları için Görsel optimizasyonu: WebP, AVIF ve lazy load yazısına bakabilirsiniz.
Reklam ve widget alanlarına yer ayırmak
Reklam alanına en sık gelen boyut kadar min-height verin. Reklam gelmezse boşluk kalır; bu, kaymadan iyidir. Görünür alanın en üstüne dinamik reklam koymamak da ayrıca işe yarar.
/* Mobilde 250 px yüksekliğinde reklam bekleniyor */
.reklam-alani { min-height: 250px; }
@media (min-width: 768px) { .reklam-alani { min-height: 90px; } }Bantları içeriği itmeyecek şekilde göstermek
Çerez bildirimi ve kampanya bantları için benim kuralım şu: ya sunucudan HTML içinde gelsin ve baştan yeri olsun, ya da position: fixed ile içeriğin üzerinde bir katman (overlay) olarak görünsün. Belge akışına sonradan eklenip içeriği iten bant kabul edilemez.
Font kaynaklı kaymayı azaltmak
Yedek fontu web fontuna benzetmek için @font-face içindeki size-adjust, ascent-override, descent-override ve line-gap-override tanımlayıcılarını kullanabilirsiniz. Aşağıdaki değerler örnektir; kendi fontunuz için hesaplamanız gerekir. Bazı framework'ler ve font araçları bu değerleri otomatik üretir.
/* Yedek font, web fontunun ölçülerine yaklaştırılır (değerler örnektir) */
@font-face {
font-family: "Inter Yedek";
src: local("Arial");
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
body { font-family: "Inter", "Inter Yedek", sans-serif; }Kritik fontu önceden yüklemek (preload) ve font-display: optional kullanmak da kaymayı azaltır; optional, font geç gelirse o sayfa görüntülemesinde yedek fontta kalır.
Animasyonlarda transform kullanmak
Bir elemanı kaydırmak, büyütmek veya açmak için transform: translate() ve transform: scale() kullanın. Bunlar layout'u etkilemez ve genellikle daha akıcı çalışır.
Kaymaları bulmak
Önce Search Console'daki Önemli Web Verileri (Core Web Vitals) raporundan hangi URL gruplarının etkilendiğine bakıyorum. Sonra sorunu kendi tarayıcımda yeniden üretmeye çalışıyorum.
- DevTools > Rendering sekmesi > Layout Shift Regions: Bu seçeneği açtığınızda kayan alanlar anlık olarak renkli vurgulanır.
- DevTools > Performance paneli: Kayıt aldığınızda layout shift'ler zaman çizelgesinde ayrı bir izde görünür; güncel sürümlerdeki Insights bölümü kaymaya yol açan olası sebepleri (culprits) de listeliyor.
- PerformanceObserver: Hangi düğümün kaydığını ve oturum penceresi değerini konsolda görmek için aşağıdaki kodu kullanıyorum.
Konsolda node üzerine gelince eleman sayfada vurgulanır. Çoğu zaman kayan eleman sorunun kendisi değil, onun üstüne sonradan eklenen bir şeydir; kayan elemanın hemen üstündeki kardeşine bakın.
Gerçek kullanıcılardan veri toplamak için web-vitals kütüphanesinin attribution sürümündeki onCLS fonksiyonu, en büyük kaymaya yol açan elemanı raporlar. Aynı yaklaşımı INP için INP'yi düzeltmek yazısında anlattım.
Laboratuvar testinin bir sınırı var: Lighthouse sadece yükleme sırasındaki kaymaları görür. Kaydırırken yüklenen reklamlar veya birkaç saniye sonra açılan bantlar sahada CLS üretir ama laboratuvarda görünmeyebilir. Bu yüzden sayfayı gerçekten kaydırarak, mobil görünümde ve yavaş ağ ayarıyla test edin.
Kontrol listesi
- Tüm
<img>ve<iframe>elemanlarındawidth/heightveya CSSaspect-ratiovar. - Reklam ve widget alanlarına
min-heightile yer ayrıldı. - Çerez bildirimi ve kampanya bantları içeriği itmiyor; ya baştan yerleri var ya da overlay.
- Web fontları için yedek font ayarlandı veya
font-display: optionaldeğerlendirildi. - Animasyonlar
transformile yapılıyor, layout özellikleriyle değil. - Hover ile açılan ve içeriği iten eleman yok.
- DevTools'ta Layout Shift Regions açıkken sayfa baştan sona kaydırılarak test edildi.
- Saha verisi için PerformanceObserver veya web-vitals ile kaynak elemanlar toplanıyor.
Comments / questions
If you have a question about any topic or wish to contact me: Telegram or send an email to [email protected] Thanks!