top of page

getBoundingClientRect Nedir, Nasıl Kullanılır?


Özet: - getBoundingClientRect, bir DOM öğesinin viewport'a göre konumunu ve boyutunu DOMRect olarak döndürür. - DOMRect nesnesi top, right, bottom, left, width, height ile x ve y alanlarını taşır. - Değerler kaydırmayla değişir, mutlak sayfa konumu için window.scrollY ve scrollX eklenir. - Scroll olayı içinde sık çağrı reflow tetikler, bu yüzden görünürlük takibinde IntersectionObserver tercih edilir. - Tooltip, sticky menü ve sürükle-bırak gibi konum hesabı gerektiren her işte temel ölçüm aracıdır.


İçindekiler


  • getBoundingClientRect tam olarak neyi ölçer

  • DOMRect nesnesinin alanları ve okunması

  • Viewport koordinatından sayfa koordinatına geçiş

  • Tooltip ve açılır menü konumlamada pratik kullanım

  • Sticky navigasyon ve sonsuz kaydırma senaryosu

  • Reflow tuzağı ve IntersectionObserver alternatifi

  • React ve bileşen tarafında ölçüm zamanlaması

  • Sık tekrarlanan hatalar ve kaçınma yolları

  • Sık Sorulan Sorular

  • Kaynakça


Bir butonun yanına ipucu kutusu açmak istediniz. Kutu ekranın dışına taştı. Ya da bir menüyü belirli bir noktada sabitlemeye çalıştınız, hep yanlış yere oturdu. Bu sorunların hepsi tek bir soruya bağlanır: o öğe şu anda ekranda tam olarak nerede? Tarayıcı bu sorunun cevabını sakladığı yerden vermez, ölçmenizi bekler. İşte bu ölçümü yapan metot tarayıcının kendi içinde hazır durur.


JavaScript tarafında bir elemanın gerçek konumunu öğrenmenin en doğrudan yolu vardır. CSS'te `top` ya da `left` yazmak öğeyi konumlandırır, ama o öğenin ekranda hangi piksele denk geldiğini söylemez. Çünkü araya kaydırma, üst öğelerin boşlukları, dönüşümler ve responsive kırılımlar girer. Ölçülen değer ile yazdığınız değer çoğu zaman aynı değildir.


getBoundingClientRect tam olarak neyi ölçer


`Element.getBoundingClientRect()` çağrıldığında, çağrıldığı öğenin görünen pencereye (viewport) göre konumunu ve boyutunu döndürür. MDN bunu öğeyi çevreleyen en küçük dikdörtgen olarak tanımlar. Yani öğenin kenar kutusu (border-box) baz alınır ve bu kutunun sınırları piksel cinsinden okunur.


Önemli olan referans noktasıdır. Dönen değerler sayfanın en üstüne göre değil, o anda gördüğünüz pencerenin sol üst köşesine göre verilir. Sayfayı aşağı kaydırırsanız aynı öğe için okunan `top` değeri küçülür. Kaydırma yukarı çıktıkça büyür. Bu davranış kafa karıştırabilir, ama mantığı basittir: metot size öğenin ekranda nerede durduğunu söyler, belgede nerede durduğunu değil.


W3C'nin CSSOM View Module taslağı da aynı tanımı verir. Metot, öğenin yerleşim kutularının birleşiminden oluşan sınırı döndürür. Tek satırlık bir öğede tek dikdörtgen çıkar. Birden çok satıra yayılan satır içi (inline) bir öğede ise tüm parçaları kapsayan dış sınır döner.


DOMRect nesnesinin alanları ve okunması


Metot bir sayı değil, bir DOMRect nesnesi döndürür. Bu nesnenin içinde öğenin geometrisini anlatan değerler bulunur. Hepsi piksel cinsindendir ve modern tarayıcılarda ondalık (subpixel) değer alabilir.


  • Alan — Anlamı

  • `top` — Üst kenarın viewport üstüne uzaklığı

  • `bottom` — Alt kenarın viewport üstüne uzaklığı

  • `left` — Sol kenarın viewport soluna uzaklığı

  • `right` — Sağ kenarın viewport soluna uzaklığı

  • `width` — Öğenin genişliği

  • `height` — Öğenin yüksekliği

  • `x` / `y` — left ve top ile aynı başlangıç noktası


Okuması kısadır:


const kutu = document.querySelector(".kart");
const rect = kutu.getBoundingClientRect();
console.log(rect.top, rect.left, rect.width, rect.height);


Burada `rect.x` ile `rect.left` aynı değeri verir, `rect.y` ile `rect.top` da öyle. İkisinin birlikte bulunması eski ve yeni kodun aynı anda çalışabilmesi içindir. Pratikte `top` ve `left` daha sık tercih edilir, çünkü okurken niyet daha açıktır.


Viewport koordinatından sayfa koordinatına geçiş


Çoğu hata burada başlar. Öğeyi sayfanın en üstüne göre konumlamak isteyen geliştirici, doğrudan `rect.top` değerini kullanır ve sayfa kaydıkça konum kayar. Sebep nettir: o değer pencereye göredir, belgeye göre değil.


Belgeye göre mutlak konumu bulmak için o anki kaydırma miktarını eklemek gerekir. MDN bunu açıkça söyler: belgenin sol üst köşesine göre dikdörtgen istiyorsanız mevcut kaydırma konumunu, yani `window.scrollX` ve `window.scrollY` değerlerini ekleyin.


const rect = kutu.getBoundingClientRect();
const sayfaUstu = rect.top + window.scrollY;
const sayfaSolu = rect.left + window.scrollX;


Bu küçük ekleme, kaydırmadan bağımsız sabit bir koordinat verir. Sayfa neresinde olursa olsun aynı öğe için aynı `sayfaUstu` değeri okunur. Sticky bir öğeyi belgeye göre işaretlemek ya da bir konumu kaydedip sonra geri dönmek istediğinizde bu dönüşüm şarttır.


Tooltip ve açılır menü konumlamada pratik kullanım


Bir ipucu kutusunu butonun hemen altına yerleştirmek istiyorsunuz. Butonun ekrandaki yerini bilmeden bunu yapamazsınız. İşte metot tam da bunu çözer: referans öğenin sınırlarını okur, kutuyu o sınırlara göre konumlarsınız.


const buton = document.querySelector(".ipucu-tetik");
const tooltip = document.querySelector(".tooltip");
const r = buton.getBoundingClientRect();

tooltip.style.top = `${r.bottom + 8}px`;
tooltip.style.left = `${r.left}px`;


Asıl mesele taşmadır. Buton ekranın sağ kenarına yakınsa, kutu dışarı çıkar. Burada `r.right` değerini pencere genişliğiyle karşılaştırırsınız. Taşma varsa kutuyu sola hizalarsınız. Aynı mantık dikeyde de geçerlidir: alt kenara yakın bir tetikleyicide kutuyu yukarı açarsınız. Chrome'un anchor positioning yazısı, bu hesabın yıllarca JavaScript ile yapıldığını, öğelerin birbirine bu ölçümle bağlandığını anlatır.


Açılır menülerde, bağlam menülerinde ve sürükle-bırak arayüzlerinde de aynı yaklaşım çalışır. javascript.info'nun sürükle-bırak rehberi, taşınan öğenin sınırlarını bu metotla okuyarak imlecin öğe içindeki ofsetini hesaplar. Konum bilgisi olmadan akıcı bir sürükleme deneyimi kurmak mümkün değildir.


Sticky navigasyon ve sonsuz kaydırma senaryosu


Bir menüyü belirli bir kaydırma noktasında sabitlemek isteyebilirsiniz. Klasik yöntem, hedef öğenin `top` değerini izlemektir. Değer sıfırın altına düştüğünde öğe pencerenin üstünü geçmiş demektir, menüyü sabit konuma alırsınız.


Görünürlük kontrolü de benzer kurar. Bir öğenin ekranda olup olmadığını anlamak için `top` değerini `window.innerHeight` ile karşılaştırırsınız. `top` pencere yüksekliğinden küçük ve `bottom` sıfırdan büyükse, öğe en azından kısmen görünüyordur. Sonsuz kaydırma listelerinde bu kontrol bir sentinel (gözcü) öğeye bağlanır: gözcü görünür alana girdiğinde yeni içerik yüklenir.


Bu yaklaşım çalışır, ama bir bedeli vardır. Her kaydırma olayında ölçüm yapmak performansı zorlar. Bir sonraki bölümde tam olarak neden olduğuna ve modern çözüme bakalım.


Reflow tuzağı ve IntersectionObserver alternatifi


getBoundingClientRect bir okuma işlemidir, ama masum bir okuma değildir. Tarayıcının bekleyen yerleşim hesaplarını o anda zorla bitirmesini ister. Buna forced synchronous layout ya da reflow denir. Google'ın render performansı rehberi, geometri okuyan API'lerin bekleyen layout'u senkron tetiklediğini açıkça yazar.


Asıl sorun döngüde çıkar. Bir döngü içinde önce ölçüp sonra stil değiştirir, sonra tekrar ölçerseniz, tarayıcı her turda yeniden hesap yapar. Buna layout thrashing denir ve sayfayı gözle görülür biçimde takırdatır. Çözüm okuma ve yazmayı ayırmaktır: önce tüm ölçümleri toplu alın, sonra tüm değişiklikleri uygulayın.


Görünürlük takibi içinse daha iyi bir yol var. IntersectionObserver, bir öğenin viewport ya da bir ata öğeyle kesişimini asenkron olarak izler. Ana iş parçacığını bloklamaz, kaydırma olayına gerek bırakmaz.


const gozlemci = new IntersectionObserver((girisler) => {
  girisler.forEach((giris) => {
    if (giris.isIntersecting) yukle();
  });
});
gozlemci.observe(document.querySelector(".gozcu"));


Bu yapı, sonsuz kaydırma ve tembel yükleme (lazy load) için doğru araçtır. getBoundingClientRect'i ise anlık ve tek seferlik ölçümler için, animasyon karesi dışında saklamak en sağlıklı tercihtir. blakfy.com'daki ilk anlatımda da vurguladığımız ayrım budur: ölçümü hesabın gerektiği ana bırakın, her kaydırmaya değil.


React ve bileşen tarafında ölçüm zamanlaması


Bileşen tabanlı arayüzlerde bir başka soru çıkar: ölçümü ne zaman yapmalı? DOM henüz boyanmadan ölçerseniz değer hazır olmayabilir. Boyandıktan sonra ölçüp konum değiştirirseniz kullanıcı titremeyi (flicker) görür.


React bu yüzden `useLayoutEffect` sağlar. Resmi React belgeleri bu kancanın tarayıcı ekranı boyamadan önce senkron çalıştığını söyler. Yani öğeyi `useLayoutEffect` içinde ölçüp konumu aynı karede ayarlarsanız, kullanıcı ara adımı hiç görmez.


useLayoutEffect(() => {
  const r = ref.current.getBoundingClientRect();
  setKonum({ top: r.bottom, left: r.left });
}, []);


Aynı ilke framework'süz kodda da geçerlidir. Ölçüm ile DOM değişikliğini olabildiğince yakın tutun, tercihen aynı işlem bloğunda. Ölçtüğünüz değer ile uyguladığınız değer arasına bir paint girerse, görsel sıçrama kaçınılmaz olur.


Sık tekrarlanan hatalar ve kaçınma yolları


Bu metotla çalışırken birkaç hata sürekli geri döner. İlki referans karışıklığıdır. Geliştirici viewport koordinatını sayfa koordinatı sanır ve kaydırma payını eklemeyi unutur. Sonuç, sayfa kayınca yerinden oynayan bir tooltip olur. Çözüm tek satırlık bir alışkanlıktır: belge konumu gerekiyorsa her zaman scrollY ve scrollX ekleyin.


İkinci hata ölçüm zamanlamasıdır. Öğe henüz DOM'a eklenmeden ya da gizliyken (`display: none`) getBoundingClientRect çağırırsanız, dönen DOMRect sıfır değerlerle gelir. Çünkü gizli öğenin yerleşim kutusu yoktur. Önce öğeyi görünür kılın, sonra ölçün. Aynı şekilde bir resmin ya da yazı tipinin yüklenmesi öğenin boyutunu değiştirebilir, bu yüzden getBoundingClientRect çağrısını yükleme tamamlandıktan sonraya bırakmak gerekir.


Üçüncü ve en pahalı hata döngü içinde ölçüm yapmaktır. Bir liste içindeki her öğe için sırayla ölçüp stil değiştirmek, tarayıcıyı her turda yeniden hesaplamaya zorlar. Bunun yerine tüm ölçümleri tek seferde toplayın, sonra tüm yazmaları uygulayın. Bu basit ayrım, takılan bir arayüzü akıcı hale getirir.


Bir metodun ne döndürdüğünü bilmek başlangıçtır, ama esas ustalık onu ne zaman çağıracağını bilmektir. getBoundingClientRect size öğenin ekrandaki yerini eksiksiz verir. Karşılığında ölçümü doğru ana yerleştirmenizi, gereksiz tekrarı kesmenizi ve mümkün olan yerde observer'lara devretmenizi bekler. Bu dengeyi kuran arayüz hem doğru konumlar hem akıcı kalır.


Sık Sorulan Sorular


getBoundingClientRect değeri neden sayfayı kaydırınca değişiyor?


Çünkü dönen değerler belgeye değil, görünen pencereye göredir. Kaydırma ilerledikçe öğenin pencere içindeki yeri değişir, bu yüzden `top` ve `bottom` değerleri de değişir. Bu hatalı bir durum değildir, metodun tasarımı tam olarak böyledir. Sabit bir sayfa koordinatı istiyorsanız okuduğunuz değere o anki kaydırma miktarını eklersiniz.


Mutlak sayfa konumunu nasıl hesaplarım?


`rect.top + window.scrollY` ile dikey, `rect.left + window.scrollX` ile yatay mutlak konumu bulursunuz. Bu toplam, kaydırma durumundan bağımsız sabit bir değer verir. Bir öğenin yerini kaydedip kullanıcı sayfayı gezdikten sonra aynı noktaya geri dönmek istediğinizde bu hesap işinizi kurtarır.


Bir öğenin ekranda görünüp görünmediğini bu metotla anlayabilir miyim?


Anlayabilirsiniz. `top` değeri `window.innerHeight` değerinden küçük ve `bottom` değeri sıfırdan büyükse öğe kısmen görünür. Tam görünürlük için ek olarak `top` değerinin sıfırdan büyük olmasını da kontrol edersiniz. Ancak sürekli takip için IntersectionObserver daha performanslıdır, çünkü her kaydırmada ölçüm yapmaz.


getBoundingClientRect performansı neden etkiler?


Bu çağrı tarayıcının bekleyen yerleşim hesaplarını zorla bitirmesini ister, buna reflow denir. Tek seferlik kullanımda sorun yoktur. Bir döngü ya da kaydırma olayı içinde sürekli çağırmak ise layout thrashing'e ve gözle görülür takılmaya yol açar. Çare, ölçüm ve yazma işlemlerini ayırıp ölçümleri toplu almaktır.


IntersectionObserver mı yoksa getBoundingClientRect mı kullanmalıyım?


Görünürlük ve kesişim takibi için IntersectionObserver, anlık ve tek seferlik konum ölçümü için getBoundingClientRect. İlki asenkron çalışır ve ana iş parçacığını yormaz, ikincisi ise belirli bir anda kesin geometri verir. Çoğu modern arayüzde ikisi birlikte kullanılır: gözlemci ne zaman ölçüleceğini, metot da o an tam değeri söyler.


Negatif top değeri ne anlama gelir?


Öğenin üst kenarı pencerenin üstünü geçmiş demektir. Yani kullanıcı o öğeyi yukarıda bırakacak kadar aşağı kaydırmıştır. Sticky davranışı tetiklemek için en sık izlenen sinyallerden biri budur: değer sıfırın altına düştüğü an öğeyi sabitlersiniz.


Kaynakça



 
 
bottom of page