İstemci ipuçlarıyla kaynak seçimini otomatikleştirme

Ilya Grigorik
Ilya Grigorik

Web için uygulama geliştirme, benzersiz bir erişim sağlar. Web uygulamanız bir tık uzağınızda ve marka veya platform fark etmeksizin, hemen hemen her bağlı cihaz (akıllı telefon, tablet, dizüstü bilgisayar, masaüstü bilgisayar, TV) ile kullanılabilir. En iyi deneyimi sunmak amacıyla, sunumu ve işlevi her form faktörüne göre uyarlayan duyarlı bir site oluşturdunuz ve artık uygulamanın mümkün olduğunca hızlı yüklendiğinden emin olmak için performans listenizi çalıştırıyorsunuz: kritik yolunuzu optimize ettiniz, metin kaynaklarınızı sıkıştırıp önbelleğe aldınız ve artık hesap kaynaklarınızı genellikle büyük ölçüde aktarıyorsunuz. Sorun, resim optimizasyonu zordur:

  • Uygun biçimi belirleme (vektör veya kafes)
  • En uygun kodlama biçimlerini (jpeg, webp vb.) belirlemek
  • Doğru sıkıştırma ayarlarını belirleme (kayıplı veya kayıpsız)
  • Hangi meta verilerin saklanması veya kaldırılması gerektiğini belirleyin
  • Her ekran + DPR çözünürlüğü için her birinin birden fazla varyantını oluşturun
  • ...
  • Kullanıcının ağ türünü, hızını ve tercihlerini hesaba katın

Bunlar tek tek iyi anlaşılan sorunlardır. Toplu olarak, biz (geliştiriciler) genellikle gözden kaçırdığımız veya ihmal ettiğimiz geniş bir optimizasyon alanı oluştururlar. İnsanlar, özellikle de birçok adımın gerekli olduğu durumlarda aynı arama alanını tekrar tekrar keşfetme konusunda kötü bir iş yapar. Öte yandan bilgisayarlar bu tür görevlerde uzmandır.

Resimler ve benzer özelliklere sahip diğer kaynaklar için iyi ve sürdürülebilir bir optimizasyon stratejisinin yanıtı basittir: otomasyon. Kaynaklarınızı el ile ayarlıyorsanız yanılıyorsunuz. Unutacaksınız, tembel olacaksınız veya bir başkası bu hatayı sizin yerinize yapacak.

Performansa dikkat eden geliştiricinin hikayesi

Görsel optimizasyon alanında arama, iki farklı aşamadan oluşur: derleme zamanı ve çalışma zamanı.

  • Örneğin uygun biçimi ve kodlama türünü seçme, her kodlayıcı için sıkıştırma ayarlarını ayarlama, gereksiz meta verileri çıkarma vb. gibi bazı optimizasyonlar kaynağın doğasında vardır. Bu adımlar "derleme zamanında" gerçekleştirilebilir.
  • Diğer optimizasyonlar, istekte bulunan istemcinin türüne ve özelliklerine göre belirlenir ve "çalışma zamanında" gerçekleştirilmelidir: istemcinin DPR'si ve hedeflenen görüntü genişliği için uygun kaynağın seçilmesi, müşterinin ağ hızı, kullanıcı ve uygulama tercihleri vb. dikkate alınır.

Derleme zamanı araçları mevcuttur ancak daha iyi hale getirilebilir. Örneğin, her bir resim ve her bir resim biçimi için "kalite" ayarının dinamik olarak ayarlanmasıyla çok sayıda tasarruf elde edilebilir ancak henüz kimse bunları araştırma dışında gerçekten kullandığını görmedim. Bu, yenilik için elverişli bir alandır, ancak bu gönderinin amacına uygun olarak burada bırakacağım. Hikayenin çalışma zamanı bölümüne odaklanalım.

<img src="/image/thing" sizes="50vw"
        alt="image thing displayed at 50% of viewport width">

Uygulamanın amacı çok basittir: Resmi kullanıcının görüntü alanının% 50'sinde getirin ve görüntüleyin. Çoğu tasarımcı bara gelmek için ellerini ve kafalarını yıkadığı yerdir. Bu sırada ekipteki performansa önem veren geliştirici ise uzun bir gece boyunca çalışıyor:

  1. En iyi sıkıştırmayı elde etmek üzere her istemci için optimum resim biçimini kullanmak istiyor: Chrome için WebP, Edge için JPEG XR ve diğerleri için JPEG.
  2. En iyi görsel kaliteyi elde etmek için her resmin farklı çözünürlüklerde birden fazla varyantını oluşturması gerekiyor: 1x, 1,5x, 2x, 2,5x, 3x ve hatta bu ikisi arasında birkaç tane daha.
  3. Gereksiz pikseller yayınlamaktan kaçınmak için "kullanıcının görüntü alanının% 50'sinin aslında ne anlama geldiğini" anlaması gerekiyor. Çok sayıda farklı görüntü alanı genişliği var.
  4. İdeal olarak, daha yavaş ağlardaki kullanıcıların otomatik olarak daha düşük bir çözünürlük getireceği dayanıklı bir deneyim de sunmak ister. Sonuçta her şey göz önünde bulundurmak.
  5. Uygulama, hangi resim kaynağının getirileceğini etkileyen bazı kullanıcı denetimlerini de gösterir. Bu yüzden bu kontrollerin de hesaba katılması gerekir.

Sonra tasarımcı, okunabilirliği optimize etmek için görüntü alanının küçük olması durumunda% 100 genişlikte farklı bir resim göstermesi gerektiğini fark ediyor. Bu, aynı işlemi bir öğe için daha tekrarlamamız ve ardından getirme işlemini görüntü alanı boyutuna göre koşullu hale getirmemiz gerektiği anlamına gelir. Bunun zor olduğundan bahsetmiş miydim? Evet, şimdi yapalım. picture öğesi, neredeyse o mesafeyi halletmemizi sağlar:

<picture>
    <!-- serve WebP to Chrome and Opera -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w"
    type="image/webp">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w"
    type="image/webp">
    <!-- serve JPEGXR to Edge -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
        /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
        /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w,
        /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w,
        /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
    <!-- serve JPEG to others -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
    <!-- fallback for browsers that don't support picture -->
    <img src="/image/thing.jpg" width="50%">
</picture>

Görsel yönü ve biçim seçimini inceledik ve müşterinin cihazının görüntü alanı genişliği ve DPR'deki değişkenliği hesaba katmak için her resmin altı varyantını sunduk. Etkileyici!

Maalesef picture öğesi, istemcinin bağlantı türüne veya hızına göre nasıl davranması gerektiğine dair herhangi bir kural tanımlamamıza izin vermiyor. Bununla birlikte, işleme algoritması bazı durumlarda kullanıcı aracısının hangi kaynağı getireceğini ayarlamasına izin verir (5. adıma bakın). Kullanıcı aracısının yeterince akıllı olduğunu umarız. (Not: Mevcut uygulamaların hiçbiri bu değildir). Benzer şekilde, picture öğesinde, uygulama veya kullanıcı tercihlerini dikkate alan uygulamaya özel mantığa izin veren kancalar yoktur. Bu son iki biti elde etmek için yukarıdaki mantığın tümünü JavaScript'e taşımamız gerekirdi, ancak bu da picture tarafından sunulan önyükleme tarayıcı optimizasyonlarını ortadan kaldırır. Hata.

Bu sınırlamaları bir kenara bırakarak, işe yarıyor. En azından bu belirli bir öğe için. Buradaki gerçek ve uzun vadeli zorluk, tasarımcının veya geliştiricinin her bir öğe için böyle bir kod oluşturmasını bekleyemeyiz. İlk denemede eğlenceli bir zeka bulmacası olsa da ilk denemenizden sonra etkisini yitiriyor. Otomasyona ihtiyacımız var. Belki de IDE'nin veya diğer içerik dönüştürme araçları bizi kurtarabilir ve yukarıdaki ortak metni otomatik olarak oluşturabilir.

İstemci ipuçlarıyla kaynak seçimini otomatikleştirme

Derin bir nefes alın, inançlarınızı susturun ve şimdi aşağıdaki örneği düşünün:

<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">
...
<picture>
    <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing">
    <img sizes="100vw" src="/image/thing-crop">
</picture>

Belki inanın, ister inanmayın, yukarıdaki örnek, yukarıdaki çok daha uzun olan resim işaretleme ile aynı yetenekleri sunmak için yeterlidir. "Sihir", istemci ipucu raporlamasını etkinleştiren ve tarayıcıya, sunucuya kaynakların cihaz piksel oranını (DPR), düzen görüntü alanı genişliğini (Viewport-Width) ve istenen görüntüleme genişliğini (Width) bildirmesini bildiren ilk satırdadır.

İstemci ipuçları etkinleştirildiğinde, elde edilen istemci tarafı işaretleme yalnızca sunu gereksinimlerini korur. Tasarımcının görüntü türleri, istemci çözünürlükleri, teslim edilen bayt miktarını azaltmak için en uygun ayrılma noktaları veya diğer kaynak seçim ölçütleri konusunda endişelenmesine gerek yoktur. Kabul edelim, bunu hiç yapmadılar ve artık yapmamalılar. Daha da iyisi, gerçek kaynak seçimi istemci ve sunucu tarafından anlaşıldığından geliştiricinin yukarıdaki işaretlemeyi yeniden yazması ve genişletmesi gerekmez.

Chrome 46; DPR, Width ve Viewport-Width ipuçları için yerel destek sağlar. İpuçları varsayılan olarak devre dışıdır ve yukarıdaki <meta http-equiv="Accept-CH" content="...">, Chrome'a belirtilen üstbilgileri giden isteklere eklemesini bildiren bir etkinleştirme sinyali olarak işlev görür. Ardından, örnek bir resim isteği için istek ve yanıt başlıklarını inceleyelim:

İstemci ipuçlarıyla ilgili pazarlık diyagramı

Chrome, WebP biçimi desteğini Kabul etme isteği başlığı aracılığıyla; yeni Edge tarayıcısı da Kabul başlığı aracılığıyla JPEG XR desteğinin reklamını yapar.

Sonraki üç istek başlığı, istemcinin cihazının piksel oranını (3x), düzen görüntü alanı genişliğini (460 piksel) ve kaynağın amaçlanan görüntüleme genişliğini (230 piksel) tanıtan istemci ipucu başlıklarıdır. Böylece, önceden oluşturulmuş kaynakların kullanılabilirliği, bir kaynağı yeniden kodlama veya yeniden boyutlandırma maliyeti, kaynağın popülerliği, mevcut sunucu yükü gibi kendi politika kümesine göre optimum görüntü varyantını seçmesi için sunucuya gerekli tüm bilgiler sağlanır. Bu özel durumda sunucu, DPR ve Width ipuçlarını kullanır ve Content-Type, Content-DPR ve Vary üstbilgileriyle belirtildiği gibi bir WebP kaynağı döndürür.

Burada sihirli bir değnek yok. Kaynak seçimini HTML işaretlemesinden ve istemci ile sunucu arasındaki istek-yanıt pazarlığına taşıdık. Sonuç olarak, HTML yalnızca sunum gereksinimleriyle ilgilidir ve her tasarımcı ile geliştiricinin yazmasına güvenebileceğimiz bir şeydir. Resim optimizasyonu alanında yapılan arama ise bilgisayarlara aittir ve artık geniş ölçekte kolayca otomatik hale getirilmektedir. Performansa dikkat eden geliştiricimizi hatırlıyor musunuz? Şimdi işi, sağlanan ipuçlarından yararlanıp uygun yanıtı döndüren bir görüntü hizmeti yazmak. İstediği dili veya sunucuyu kullanabilir ya da bu işlemi kendi adına üçüncü taraf bir hizmetin veya CDN'nin yapmasına izin verebilir.

<img src="/image/thing" sizes="50vw"
        alt="image thing displayed at 50% of viewport width">

Ayrıca, yukarıdaki kişiyi hatırlıyor musun? Müşteri ipuçları sayesinde, sade resim etiketi artık ek işaretleme olmadan DPR, görüntü alanı ve genişliğe duyarlı hale geliyor. Resimli yön eklemeniz gerekiyorsa yukarıda gösterildiği gibi picture etiketini kullanabilirsiniz. Aksi takdirde, mevcut resim etiketlerinizin tümü çok daha akıllı hale gelir. Müşteri ipuçları mevcut img ve picture öğelerini iyileştirir.

Service Worker ile kaynak seçimi üzerinde kontrolü elinize alma

ServiceWorker, aslında tarayıcınızda çalışan istemci taraflı bir proxy'dir. Tüm giden istekleri karşılar ve yanıtları incelemenize, yeniden yazmanıza, önbelleğe almanıza ve hatta sentezlemenize olanak tanır. Görüntüler farklı değildir ve istemci ipuçları etkinleştirildiğinde etkin ServiceWorker görüntü isteklerini tanımlayabilir, sağlanan istemci ipuçlarını inceleyebilir ve kendi işleme mantığını tanımlayabilir.

self.onfetch = function(event) {
    var req = event.request.clone();
    console.log("SW received request for: " + req.url)
    for (var entry of req.headers.entries()) {
    console.log("\t" + entry[0] +": " + entry[1])
    }
    ...
}
serviceWorker için istemci ipuçları

ServiceWorker, kaynak seçimi üzerinde istemci tarafında tam kontrol sağlar. Bu çok önemli. Yapabilecekleriniz neredeyse sonsuz sayıda olduğundan bu konuyu ele alalım.

  • Kullanıcı aracısı tarafından ayarlanan istemci ipucu başlık değerlerini yeniden yazabilirsiniz.
  • İsteğe yeni istemci ipucu başlığı değerleri ekleyebilirsiniz.
  • URL'yi yeniden yazabilir ve resim isteğini alternatif bir sunucuya (ör. CDN) yönlendirebilirsiniz.
    • Hatta ipucu değerlerini başlıklardan URL'nin içine taşıyabilirsiniz. Bu şekilde altyapınızda dağıtım daha kolay hale gelir.
  • Yanıtları önbelleğe alabilir ve hangi kaynakların sunulacağı konusunda kendi mantığını tanımlayabilirsiniz.
  • Yanıtınızı, kullanıcıların bağlantısına göre uyarlayabilirsiniz.
  • Uygulama ve kullanıcı tercihi geçersiz kılmalarını hesaba katabilirsiniz.
  • Canınızın istediği her şeyi yapabilirsiniz.

picture öğesi, HTML işaretlemesinde gerekli sanat yönü kontrolünü sağlar. İstemci ipuçları, sonuçta ortaya çıkan görüntü isteklerinde ek açıklamalar sağlayarak kaynak seçimi otomasyonunu sağlar. ServiceWorker, istemcide istek ve yanıt yönetimi özellikleri sunar. Bu, genişletilebilir Web'in işleyiş şeklidir.

İstemci ipuçları ile ilgili SSS

  1. İstemci ipuçları nerelerde kullanılabilir? Chrome 46'da gönderilir. Firefox ve Edge'de dikkate alınmalıdır.

  2. İstemci ipuçları neden etkinleştirilir? İstemci ipuçlarını kullanmayacak siteler için ek yükü en aza indirmek istiyoruz. İstemci ipuçlarını etkinleştirmek için sitenin sayfa işaretlemesinde Accept-CH üst bilgisini veya eşdeğer <meta http-equiv> yönergesini sağlaması gerekir. Bu ikisinden biri mevcut olduğunda kullanıcı aracısı, uygun ipuçlarını tüm alt kaynak isteklerine ekler. Gelecekte, belirli bir kaynak için bu tercihi devam ettirecek ve gezinme isteklerinde aynı ipuçlarının sunulmasını sağlayacak ek bir mekanizma sağlayabiliriz.

  3. ServiceWorker'ımız varsa neden istemci ipuçlarına ihtiyacımız var? ServiceWorker'ın düzen, kaynak ve görüntü alanı genişliği bilgilerine erişimi yoktur. En azından, maliyetli gidiş dönüşler sunmadan ve resim isteğini önemli ölçüde geciktirmeden (ör. önceden yükleme ayrıştırıcı tarafından bir resim isteği başlatıldığında). İstemci ipuçları, istek kapsamında bu verileri kullanılabilir hale getirmek için tarayıcıyla entegre olur.

  4. İstemci ipuçları yalnızca resim kaynakları için mi kullanılabilir? DPR, Görüntü Alanı Genişliği ve Genişlik ipuçlarının temel kullanım alanı, resim öğeleri için kaynak seçimini etkinleştirmektir. Bununla birlikte, türü ne olursa olsun tüm alt kaynaklar için aynı ipuçları sunulur. Örneğin, CSS ve JavaScript istekleri de aynı bilgileri alır ve bu kaynakları optimize etmek için de kullanılabilir.

  5. Bazı resim isteklerinde Genişlik raporlanmamasının nedeni nedir? Site, resmin asıl boyutuna bağlı olduğundan, tarayıcı istenen görüntü genişliğini bilmeyebilir. Sonuç olarak, bu tür istekler ve "görüntüleme genişliği"ne sahip olmayan istekler (ör. JavaScript kaynağı) için Genişlik ipucu yoksayılır. Genişlik ipuçları almak için resimlerinizde bir boyut değeri belirttiğinizden emin olun.

  6. <insert my favorite hint> ile ilgili durum nedir? ServiceWorker, geliştiricilerin tüm giden isteklere müdahale edip bunları değiştirmelerine (ör. yeni başlıklar ekleme) olanak tanır. Örneğin, mevcut bağlantı türünü belirtmek için NetInfo tabanlı bilgiler eklemek kolaydır. "ServiceWorker ile özellik raporlaması" bölümüne bakın. Sadece SW tabanlı bir uygulama tüm resim isteklerini geciktireceği için Chrome'da gönderilen "yerel" ipuçları (DPR, Genişlik, Kaynak-Genişliği) tarayıcıda uygulanır.

  7. Nereden daha fazla bilgi edinebilir, daha fazla demo görebilirim ve ne olacak? Açıklayıcı belgeye göz atın ve geri bildiriminiz veya başka sorularınız olursa GitHub'da sorun bildirin.