Birden fazla görüntü alanı olduğunu söylesem.
BRRRRAAAAAAAMMMMMMMMM
Şu anda kullandığınız görüntü alanı, aslında görüntü alanı içindeki bir görüntü alanıdır.
BRRRRAAAAAAAMMMMMMMMM
Bazen DOM'un size verdiği veriler, bu görüntü alanlarından birine değil, diğerine başvurur.
BRRRAAAAM... ne olmuş?
Doğrudur, bir göz atın:
Düzen görüntü alanı ile görsel görüntü alanı karşılaştırması
Yukarıdaki videoda, kaydırılan ve sıkıştırılan bir web sayfası ile sağda, sayfa içindeki görüntü alanlarının konumunu gösteren bir mini harita gösterilmektedir.
Normal kaydırma sırasında her şey oldukça basittir. Yeşil alan, position: fixed
öğenin bağlı olduğu düzen görüntü alanını temsil eder.
İki parmak ucuyla yakınlaştırma kullanıldığında işler işler karışır. Kırmızı kutu, sayfanın gerçekte görebildiğimiz bölümü olan görsel görüntü alanını temsil eder. Bu görüntü alanı, position: fixed
öğeleri bulundukları yerde ve düzen görüntü alanına bağlı kalırken hareket edebilir. Düzen görüntü alanının bir sınırında kaydırma yaparsak, düzen görüntü alanını da kendisiyle birlikte sürükler.
Uyumluluğu artırma
Ne yazık ki web API'leri, başvurdukları görüntü alanı açısından tutarsızdır ve aynı zamanda tarayıcılar arasında da tutarsızdır.
Örneğin element.getBoundingClientRect().y
, düzen görüntü alanı içindeki ofseti döndürür. Çok güzel, ancak genellikle sayfadaki konumu
istiyoruz, bu yüzden şöyle yazıyoruz:
element.getBoundingClientRect().y + window.scrollY
Bununla birlikte, birçok tarayıcı window.scrollY
için görsel görüntü alanını kullanır. Bu da, kullanıcı parmaklarınızı yakınlaştırdığında yukarıdaki kodun bozulacağı anlamına gelir.
Chrome 61, window.scrollY
öğesini değiştirerek düzen görüntü alanına başvuruyor. Yani, yukarıdaki kod iki parmak ucuyla yakınlaştırıldığında bile çalışıyor. Aslında tarayıcılar, düzen görüntü alanına atıfta bulunmak için tüm konum özelliklerini yavaşça değiştirmektedir.
Bir yeni mülk hariç...
Görsel görüntü alanını komut dosyasına dönüştürme
Yeni bir API, görsel görüntü alanını window.visualViewport
olarak gösterir. Bu, tarayıcılar arası onay özellikli bir taslak spesifikasyon olup Chrome 61'de kullanıma sunulacaktır.
console.log(window.visualViewport.width);
window.visualViewport
bize şunları sağlıyor:
visualViewport tesis |
|
---|---|
offsetLeft
|
Görsel görüntü alanının sol kenarı ile düzen görüntü alanının sol kenarı arasındaki mesafe (CSS pikseli olarak). |
offsetTop
|
Görsel görüntü alanının üst kenarı ile düzen görüntü alanının arasındaki mesafe (CSS pikseli olarak). |
pageLeft
|
Görsel görüntü alanının sol kenarı ile belgenin sol sınırı arasındaki mesafe (CSS pikseli olarak). |
pageTop
|
Görsel görüntü alanının üst kenarı ile belgenin üst sınırı arasındaki mesafe (CSS pikseli olarak). |
width
|
Görsel görüntü alanının CSS piksel cinsinden genişliği. |
height
|
Görsel görüntü alanının CSS piksel cinsinden yüksekliği. |
scale
|
Sıkıştırarak yakınlaştırma ile uygulanan ölçek. İçerik, yakınlaştırma nedeniyle iki kat büyükse bu, 2 sonucunu döndürür. devicePixelRatio bu durumdan etkilenmez.
|
Ayrıca birkaç etkinlik de mevcuttur:
window.visualViewport.addEventListener('resize', listener);
visualViewport etkinlik |
|
---|---|
resize
|
width , height veya scale değiştiğinde tetiklenir.
|
scroll
|
offsetLeft veya offsetTop değiştiğinde tetiklenir.
|
Demo
Bu makalenin başındaki video visualViewport
kullanılarak oluşturulmuştur.
Chrome 61 ve sonraki sürümlerde göz atın. Mini harita çubuğunu görsel görüntü alanının sağ üst kısmına yerleştirmek için visualViewport
ve ters bir ölçek uygulayarak, iki parmak ucuyla yakınlaştırmaya rağmen her zaman aynı boyutta görünmesini sağlar.
Anladım
Etkinlikler yalnızca görsel görüntü alanı değiştiğinde tetiklenir
Söylemesi gereken bir şey gibi dursa da visualViewport
ile ilk oynadığımda bunu fark ettim.
Düzen görüntü alanı yeniden boyutlandırıldığında, görsel görüntü alanı yeniden boyutlandırılmazsa resize
etkinliği almazsınız. Bununla birlikte, düzen görüntü alanının, görsel görüntü alanı da genişlik/yükseklik değişmeden yeniden boyutlandırılması alışılmadık bir durumdur.
Asıl işin bu kısmı boşa kayıyor. Kaydırma gerçekleşirse ancak görsel görüntü alanı düzen görüntü alanına göre statik kalırsa visualViewport
ürününde bir scroll
etkinliği almazsınız ve bu çok yaygın bir durumdur. Normal doküman kaydırma sırasında görsel görüntü alanı, düzen görüntü alanının sol üst tarafında kilitli kalır. Bu nedenle scroll
, visualViewport
üzerinde tetiklenmez.
pageTop
ve pageLeft
dahil olmak üzere görsel görüntü alanında yapılan tüm değişiklikleri öğrenmek istiyorsanız pencerenin kaydırma etkinliğini de dinlemeniz gerekir:
visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
window.addEventListener('scroll', update);
Çalışmayı birden fazla dinleyiciyle tekrarlamayın
Pencerede scroll
ve resize
dinlemeye benzer şekilde, sonuç olarak bir tür "güncelleme" işlevi çağırmanız olasıdır. Ancak bu etkinliklerin birçoğunun aynı anda gerçekleşmesi yaygın bir durumdur. Kullanıcı pencereyi yeniden boyutlandırırsa resize
tetiklenir, ancak genellikle scroll
de tetiklenir. Performansı artırmak için değişikliği birden fazla kez kullanmaktan kaçının:
// Add listeners
visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
addEventListener('scroll', update);
let pendingUpdate = false;
function update() {
// If we're already going to handle an update, return
if (pendingUpdate) return;
pendingUpdate = true;
// Use requestAnimationFrame so the update happens before next render
requestAnimationFrame(() => {
pendingUpdate = false;
// Handle update here
});
}
Bunun için bir spesifikasyon sorunu oluşturdum. Tek bir update
etkinliği gibi daha iyi bir yöntem olabileceğini düşünüyorum.
Etkinlik işleyiciler çalışmıyor
Bir Chrome hatası nedeniyle bu özellik çalışmaz:
Buggy: Bir etkinlik işleyici kullanır
visualViewport.onscroll = () => console.log('scroll!');
Bunun yerine:
Çalışır: Bir etkinlik işleyici kullanır
visualViewport.addEventListener('scroll', () => console.log('scroll'));
Göreli konum değerleri yuvarlanır
Bunun başka bir Chrome hatası olduğunu düşünüyorum.
offsetLeft
ve offsetTop
yuvarlanır. Bu, kullanıcı yakınlaştırdıktan sonra oldukça doğru bir hatadır. Bu sorunları demo sırasında görebilirsiniz. Kullanıcı görüntüyü yakınlaştırıp yavaşça kaydırırsa mini harita, yakınlaştırılmamış piksellerin arasına tutturulur.
Etkinlik hızı düşük
Diğer resize
ve scroll
etkinlikleri gibi bunlar da özellikle mobil cihazlarda her kareyi tetiklemez. Bunu demo sırasında görebilirsiniz. İki parmak ucunuzu yakınlaştırdığınızda mini harita, görüntü alanına kilitli kalmakta zorlanır.
Erişilebilirlik
Demoda kullanıcının parmak ucunuzu yakınlaştırma hareketiyle
yakınlaştırma hareketini engellemek için visualViewport
kullandım. Bu demo için bir anlam ifade ediyor olabilir, ancak kullanıcının
yakınlaştırma isteğini geçersiz kılacak herhangi bir şey yapmadan önce dikkatli düşünmelisiniz.
visualViewport
, erişilebilirliği iyileştirmek için kullanılabilir. Örneğin, kullanıcı görüntüyü yakınlaştırıyorsa rahatsız olması için dekoratif position: fixed
öğeleri gizlemeyi seçebilirsiniz. Yine de, kullanıcının yakından bakmaya çalıştığı
bir şeyi saklamamaya dikkat edin.
Kullanıcı görüntüyü yakınlaştırdığında bir analiz hizmetine mesaj göndermeyi düşünebilirsiniz. Bu, kullanıcıların varsayılan yakınlaştırma düzeyinde zorluk yaşadığı sayfaları belirlemenize yardımcı olabilir.
visualViewport.addEventListener('resize', () => {
if (visualViewport.scale > 1) {
// Post data to analytics service
}
});
Hepsi bu kadar! visualViewport
, bu süreçte uyumluluk sorunlarını çözen, küçük bir API'dir.