Görsel Görünüm ile tanışın

Jake Archibald
Jake Archibald

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:

Yapılmaması gerekenler

Buggy: Bir etkinlik işleyici kullanır

visualViewport.onscroll = () => console.log('scroll!');

Bunun yerine:

Yapılması gerekenler

Ç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.