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

Jake Archibald
Jake Archibald

Birden fazla görüntü alanı olduğunu söylesem ne dersiniz?

BRRRRAAAAAAAMMMMMMMMMM

Şu anda kullandığınız görüntü alanı aslında bir görüntü alanı içinde bir görüntü alanıdır.

BRRRRAAAAAAAMMMMMMMMMM

Bazen DOM'un size verdiği veriler, bu ekran alanlarından birini ifade eder ve diğerini ifade etmez.

BRRRRAAAAM… ne dediniz?

Doğru. Şuna göz atın:

Düzen görüntü alanı ve görsel görüntü alanı

Yukarıdaki videoda, bir web sayfasının kaydırıldığı ve iki parmak ucunu yakınlaştırma/uzaklaştırma hareketiyle yakınlaştırıldığı gösterilmektedir. Sağ tarafta ise sayfadaki görüntü alanlarının konumunu gösteren bir mini harita yer almaktadır.

Normal kaydırma sırasında işler oldukça basittir. Yeşil alan, position: fixed öğelerinin bağlı olduğu düzenleme görüntü alanını gösterir.

İki parmak yakınlaştırma özelliği kullanıldığında işler tuhaflaşıyor. Kırmızı kutu, sayfanın gerçekten görebildiğimiz kısmı olan görsel görüntü alanını temsil eder. Bu görüntü alanı hareket edebilirken position: fixed öğeleri, düzen görüntü alanına bağlı olarak oldukları yerde kalır. Düzen görüntü alanının sınırında kaydırma yaptığımızda düzen görüntü alanı da sürüklenir.

Uyumluluğu iyileştirme

Maalesef web API'leri, hangi görüntü alanını referans aldıkları açısından tutarlı değildir ve tarayıcılar arasında da tutarlı değildir.

Örneğin, element.getBoundingClientRect().y, layout görüntü alanındaki ofseti döndürür. Bu harika, ancak genellikle sayfadaki konumu istiyoruz. Bu nedenle şunu yazıyoruz:

element.getBoundingClientRect().y + window.scrollY

Ancak birçok tarayıcı, window.scrollY için görsel görüntü alanını kullanır. Bu nedenle, kullanıcı parmaklarıyla yakınlaştırdığında yukarıdaki kod bozulur.

Chrome 61, window.scrollY değerini düzen görüntü alanını referans alacak şekilde değiştirir. Bu nedenle, yukarıdaki kod iki parmak ucunu yakınlaştırma/uzaklaştırma işlemi uygulandığında bile çalışır. Aslında tarayıcılar, tüm konumsal özellikleri düzen görüntü alanına atıfta bulunacak şekilde yavaş yavaş değiştiriyor.

Yeni bir mülk hariç…

Görsel görüntü alanını komut dosyasına gösterme

Yeni API, görsel görüntü alanını window.visualViewport olarak gösterir. Tarayıcılar arası onay alan bu taslak spesifikasyon, Chrome 61'de kullanıma sunulacak.

console.log(window.visualViewport.width);

window.visualViewport bize şunları sağlar:

visualViewport tesis
offsetLeft Görsel görünüm alanının sol kenarı ile düzen görünüm alanı arasındaki mesafe (CSS piksel cinsinden).
offsetTop Görsel görüntü alanının üst kenarı ile düzen görüntü alanı arasındaki mesafe (CSS piksel cinsinden).
pageLeft Görsel görüntü alanının sol kenarı ile dokümanın sol sınırı arasındaki mesafe (CSS piksel cinsinden).
pageTop Görsel görüntü alanının üst kenarı ile dokümanın üst sınırı arasındaki mesafe (CSS piksel cinsinden).
width Görsel görünüm alanının CSS piksel cinsinden genişliği.
height Görsel görünüm alanının CSS piksel cinsinden yüksekliği.
scale İki parmak ucunu yakınlaştırıp uzaklaştırarak uygulanan ölçek. İçerik, yakınlaştırma nedeniyle iki kat büyükse 2 döndürülür. Bu durum devicePixelRatio'ten etkilenmez.

Ayrıca birkaç etkinlik de vardır:

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 bu videoyu inceleyebilirsiniz. Mini haritayı görsel görüntü alanının sağ üst köşesine yapıştırmak için visualViewport kullanılır ve parmak ucuyla yakınlaştırmaya rağmen her zaman aynı boyutta görünmesi için ters ölçek uygulanır.

Dikkat edilmesi gereken noktalar

Etkinlikler yalnızca görsel görüntü alanı değiştiğinde tetiklenir

Bu, açıkça belirtilmesi gereken bir şey gibi görünse de visualViewport ile ilk oynadığımda beni şaşırtmıştı.

Sayfa düzeni görüntü alanı yeniden boyutlandırılırsa ancak görsel görüntü alanı yeniden boyutlandırılmazsa resize etkinliği almazsınız. Ancak düzen görüntü alanının, görsel görüntü alanının genişlik/yükseklik değeri değişmeden yeniden boyutlandırılması normal değildir.

Asıl sorun kaydırma işlemidir. Kaydırma gerçekleşirse ancak görsel görüntü alanı düzenleme görüntü alanına göre statik kalırsa visualViewport üzerinde bir scroll etkinliği almazsınız. Bu durum oldukça yaygındır. Normal belge kaydırma sırasında görsel görüntü alanı, düzen görüntü alanının sol üst kısmına kilitli kalır. Bu nedenle scroll, visualViewport üzerinde tetiklenmez.

pageTop ve pageLeft dahil olmak üzere görsel görüntü alanındaki tüm değişiklikler hakkında bilgi edinmek istiyorsanız pencerenin kaydırma etkinliğini de dinlemeniz gerekir:

visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
window.addEventListener('scroll', update);

Birden fazla dinleyiciyle aynı işi yapma

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 çoğunun aynı anda gerçekleşmesi yaygın bir durumdur. Kullanıcı pencereyi yeniden boyutlandırırsa resize etkinleştirilir ancak sıklıkla scroll da etkinleştirilir. Performansı artırmak için değişikliği birden fazla kez işlemekten 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
    });
}

Tek bir update etkinliği gibi daha iyi bir yöntem olabileceğini düşündüğüm için bu konuda bir özellik sorunu gönderdim.

Etkinlik işleyicileri çalışmıyor

Chrome hatası nedeniyle aşağıdaki işlem çalışmaz:

Yapılmaması gerekenler:

Hata içeriyor: Etkinlik işleyici kullanıyor

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

Bunun yerine:

Yapılması gerekenler

Çalışır: Etkinlik işleyici kullanır

visualViewport.addEventListener('scroll', () => console.log('scroll'));

Ofset değerleri yuvarlanır

Bunun başka bir Chrome hatası olduğunu düşünüyorum (umarım öyledir).

offsetLeft ve offsetTop değerleri yuvarlanır. Bu nedenle, kullanıcı yakınlaştırdığında değerler oldukça hatalı olur. Bu konuyla ilgili sorunları demoda görebilirsiniz. Kullanıcı yakınlaştırıp yavaşça kaydırdığında mini harita yakınlaştırılmamış pikseller arasında atlar.

Etkinlik oranı yavaş

Diğer resize ve scroll etkinlikleri gibi bu etkinlikler de özellikle mobil cihazlarda her karede tetiklenmez. Bu durumu demo sırasında görebilirsiniz. İki parmağınızı yakınlaştırmak için yakınlaştırdığınızda mini harita, görüntü alanına kilitlenmekte sorun yaşar.

Erişilebilirlik

Demoda, kullanıcının iki parmak ucunu yakınlaştırma/uzaklaştırma hareketini önlemek için visualViewport kullandım. Bu demo için mantıklı olsa da kullanıcının yakınlaştırma isteğini geçersiz kılan herhangi bir işlem yapmadan önce dikkatlice düşünmeniz gerekir.

visualViewport, erişilebilirliği iyileştirmek için kullanılabilir. Örneğin, kullanıcı yakınlaştırma yapıyorsa dekoratif position: fixed öğeleri gizleyerek kullanıcının görüş alanından kaldırabilirsiniz. Ancak kullanıcının daha yakından incelemeye çalıştığı bir şeyi gizlemediğinize dikkat edin.

Kullanıcı yakınlaştırdığında bir analiz hizmetine gönderme yapabilirsiniz. Bu sayede, kullanıcıların varsayılan yakınlaştırma düzeyinde zorluk yaşadığı sayfaları belirleyebilirsiniz.

visualViewport.addEventListener('resize', () => {
    if (visualViewport.scale > 1) {
    // Post data to analytics service
    }
});

Hepsi bu kadar! visualViewport, uyumluluk sorunlarını çözen kullanışlı bir API'dir.