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

Ilya Grigorik

Web için geliştirme, size benzersiz bir erişim sağlar. Web uygulamanız bir tık uzağınızda ve marka veya platform ne olursa olsun bağlı cihazların, tabletlerin, dizüstü ve masaüstü bilgisayarlarınızın hemen hemen hepsinde, TV'de ve daha pek çok cihazda kullanılabilir. En iyi deneyimi sunmak için, her form faktörüne uygun sunumu ve işlevleri uyarlayan duyarlı bir site derlediniz. Şimdi de uygulamanın mümkün olduğunca hızlı yüklendiğinden emin olmak için performans kontrol listenizi oluşturuyorsunuz: kritik oluşturma yolunuzu optimize ettiniz, metin kaynaklarınızı sıkıştırıp önbelleğe aldınız ve artık genellikle aktarılan resim kaynaklarının büyük kısmına bakıyorsunuz. Resim optimizasyonu zor bir işlemdir:

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

Tek tek bu sorunlar iyi anlaşılabilir sorunlar. Bu araçlar, geliştiricilerin (geliştiriciler) genellikle göz ardı ettiğimiz veya ihmal ettiğimiz geniş bir optimizasyon alanı oluşturur. İnsanlar, özellikle de birçok adım söz konusu olduğunda aynı arama alanını tekrar tekrar keşfetme konusunda yetersiz kalırlar. Öte yandan bilgisayarlar bu tür görevlerde uzmandır.

Resimler için iyi ve sürdürülebilir bir optimizasyon stratejisinin ve benzer özelliklere sahip diğer kaynakların yanıtı basittir: otomasyon. Kaynaklarınızı manuel olarak ayarlıyorsanız yanlış yapıyorsunuz: unutursunuz, tembel olursunuz veya başka biri bu hatayı sizin yerinize yapar, kesin bir şekilde.

Performans odaklı geliştiricinin destanı

Görsel optimizasyonu alanında arama iki farklı aşamadan oluşur: derleme süresi ve çalışma süresi.

  • Bazı optimizasyonlar, kaynağın kendisine özgüdür. Örneğin, uygun biçim ve kodlama türünü seçme, her kodlayıcı için sıkıştırma ayarlarını ayarlama, gereksiz meta verileri çıkarma vb. 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: İstemcinin DPR'si ve amaçlanan görüntü genişliği için uygun kaynağın seçilmesi, istemcinin ağ hızı, kullanıcı ve uygulama tercihleri vb. hesaba katılmalıdır.

Derleme zamanı araçları mevcut, ancak daha iyi hale getirilebilir. Örneğin, her resim ve resim biçimi için "kalite" ayarını dinamik olarak ayarlayarak çok fazla tasarruf sağlanabilir, ancak henüz bunu araştırma dışında kullanan kimseyi görmüyorum. Bu, yenilik için elverişli bir alandır, ancak bu yazının amaçları doğrultusunda bu konuyu burada bırakacağım. Hikayenin süre 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 getirip görüntüleyin. Çoğu tasarımcının bar için ellerini ve kafalarını yıkadığı yer burasıdır. Bu sırada ekipteki performans odaklı geliştirici uzun bir gece yaşıyor:

  1. En iyi sıkıştırmayı elde etmek amacıyla her istemci için optimum görüntü biçimini kullanmak istiyor: Chrome için WebP, Edge için JPEG XR ve diğer istemciler için JPEG.
  2. En iyi görsel kaliteyi elde etmek için her resmin farklı çözünürlüklerde (1x, 1,5x, 2x, 2,5x, 3x) ve hatta aralarında birkaç kat daha fazla varyantını oluşturması gerekir.
  3. Gereksiz pikseller yayınlamaktan kaçınmak için "Kullanıcı görüntü alanının% 50'sinin aslında ne anlama geldiğini" anlaması gerekiyor. Kullanılabilecek çok sayıda farklı görüntü alanı genişliği var.
  4. İdeal olarak, yavaş ağlardaki kullanıcıların otomatik olarak daha düşük bir çözünürlük getireceği esnek bir deneyim sunmak da istiyor. Sonuçta her şey camdan ibaret.
  5. Uygulama, hangi resim kaynağının getirilmesi gerektiğini etkileyen bazı kullanıcı denetimleri de sunar. Bu nedenle, bu kontroller de hesaba katılır.

Ardından tasarımcı, görüntü alanı boyutu küçükse okunabilirliği optimize etmek için% 100 genişlikte farklı bir resim göstermesi gerektiğini fark eder. Bu, aynı işlemi artık 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? Tamam, haydi başlayalım. picture öğesi bizi epey ilerletecek:

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

Resim yönü ve biçim seçimini işledik ve müşteri cihazının DPR ve görüntü alanı genişliğindeki çeşitliliği hesaba katmak amacıyla her resmin altı varyantını sağladık. 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 değildir). Benzer şekilde, picture öğesinde uygulama veya kullanıcı tercihlerini dikkate alan uygulamaya özel bir mantığa izin veren herhangi bir kanca yoktur. Bu son iki biti elde etmek için yukarıdaki mantığın tamamını JavaScript'e taşımamız gerekirdi. Ancak bu, picture tarafından sunulan önceden yükleme tarayıcı optimizasyonlarını geçersiz kılar. Hata.

Bu sınırlamalar bir yana işliyor. En azından bu belirli öğe için. Buradaki gerçek ve uzun vadeli zorluk, tasarımcıdan veya geliştiriciden her öğe için bu tür kodlar elde etmesini bekleyemeyeceğimizdir. İlk denemede eğlenceli bir beyin bulmacası oluştursa da sonrasında cazibesini hemen kaybediyor. Otomasyona ihtiyacımız var. Belki de IDE'ler 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çsızlığınızı bir kenara bırakın 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>

İster inanın ister inanmayın, yukarıdaki örnek, yukarıdaki çok daha uzun resim işaretlemeyle aynı yeteneklerin tamamını sunmak için yeterlidir, göreceğiniz gibi resim kaynaklarının nasıl ve ne zaman getirileceği üzerinde tam geliştirici kontrolü sağlar. "Sihirli" ilk satırda, istemci ipuçları raporlamasını etkinleştirir ve tarayıcıya cihaz piksel oranını (DPR), düzen görüntü alanı genişliğini (Viewport-Width) ve kaynakların amaçlanan görüntü genişliğini (Width) sunucuya tanıtmasını bildirir.

İstemci ipuçları etkinleştirildiğinde elde edilen istemci taraflı işaretleme yalnızca sunum gereksinimlerini korur. Tasarımcının görüntü türleri, istemci çözünürlükleri, yayınlanan bayt sayısını azaltmak için en uygun kesme noktaları veya diğer kaynak seçim kriterleri konusunda endişesi yoktur. Kabul edelim, bunu yapmadılar ve zorlanmamaları da gerekiyor. Daha iyisi, gerçek kaynak seçimi istemci ve sunucu tarafından belirlendiği için 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 görevi görür. Şimdi örnek bir resim isteği için istek ve yanıt başlıklarını inceleyelim:

Müşteri ipuçları görüşme diyagramı

Chrome, WebP biçimini Kabul isteği başlığı üzerinden desteklediğini bildirir. Yeni Edge tarayıcısı da aynı şekilde Accept başlığı üzerinden JPEG XR desteğini bildirir.

Sonraki üç istek başlığı; istemci cihazının cihaz piksel oranını (3x), düzen görüntü alanı genişliğini (460 piksel) ve kaynağın amaçlanan görüntü genişliğini (230 piksel) tanıtan istemci ipucu başlıklarıdır. Bu işlem, ö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 politikalara göre en uygun resim varyantını seçmesi için sunucuya tüm gerekli bilgileri sağlar. Bu durumda sunucu Content-Type, Content-DPR ve Vary üstbilgilerinde belirtildiği gibi DPR ve Width ipuçlarını kullanıp bir WebP kaynağı döndürür.

Burada sihir yok. Kaynak seçimini HTML işaretlemesinden istemci ile sunucu arasındaki istek-yanıt pazarlığına taşıdık. Sonuç olarak, HTML yalnızca sunum gereksinimleriyle ilgilenir ve bunları yazma konusunda tüm tasarımcılara ve geliştiricilere güvenirken, görsel optimizasyon alanında arama bilgisayarlara ertelenir ve artık geniş ölçekte kolayca otomatik hale getirilebilir. Performans odaklı geliştiricimizi hatırlıyor musunuz? Şu anda görevi, sağlanan ipuçlarından yararlanabilen ve uygun yanıtı döndürebilen bir görüntü hizmeti yazmaktır: İstediği herhangi bir dili veya sunucuyu kullanabilir ya da bunu onun adına bir üçüncü taraf hizmetin veya CDN'nin yapmasına izin verebilir.

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

Yukarıdaki kişiyi hatırlıyor musunuz? İstemci ipuçlarıyla mütevazı resim etiketi artık ek işaretleme olmadan DPR, görüntü alanı ve genişliğe duyarlı hale geldi. Art-direction eklemeniz gerekirse, yukarıda gösterildiği gibi picture etiketini kullanabilirsiniz. Bunu yapmazsanız mevcut resim etiketlerinizin tamamı çok daha akıllı hale gelir. İstemci ipuçları mevcut img ve picture öğelerini iyileştirir.

Service Worker ile kaynak seçimi üzerinde kontrol sahibi olma

ServiceWorker aslında tarayıcınızda çalışan bir istemci tarafı proxy'dir. Giden tüm isteklere müdahale ederek yanıtları incelemenize, yeniden yazmanıza, önbelleğe almanıza ve hatta sentezlemenize olanak tanır. Görüntüler de 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 istemci ipuçları.

ServiceWorker, kaynak seçiminde istemci tarafında tam denetime sahip olmanızı sağlar. Bu çok önemli. Bırakın bunları boş bırakın, olasılık neredeyse sonsuza kadar:

  • Kullanıcı aracısı tarafından ayarlanan istemci ipuçları 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, altyapınızda dağıtımı kolaylaştıracaktır.
  • Yanıtları önbelleğe alabilir ve hangi kaynakların sunulduğuna ilişkin kendi mantığınızı tanımlayabilirsiniz.
  • Yanıtınızı kullanıcıların bağlantı durumuna göre uyarlayabilirsiniz.
  • Uygulama ve kullanıcı tercihi geçersiz kılmalarını hesaba katabilirsiniz.
  • Kalbinizin istediği her şeyi yapabilirsiniz.

picture öğesi, HTML işaretlemesinde gerekli resim yönü denetimini sağlar. İstemci ipuçları, sonuç olarak gelen resim isteklerine ek açıklamalar sağlayarak kaynak seçimi otomasyonunu etkinleştirir. ServiceWorker, istemcide istek ve yanıt yönetimi özellikleri sağlar. Genişletilebilir web'in işleyiş şekli budur.

Müşteri ipuçları SSS

  1. İstemci ipuçları nerede kullanılabilir? Chrome 46 sürümünde gönderilir. Firefox ve Edge'de dikkate alınmamaktadır.

  2. Müşteri ipuçlarını neden etkinleştirmesi gerekiyor? İstemci ipuçlarını kullanmayan sitelerin ek yükünü 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. Bunlardan biri mevcutsa kullanıcı aracısı, uygun ipuçlarını tüm alt kaynak isteklerine ekler. Gelecekte, belirli bir kaynak için bu tercihi sürdürmek amacıyla ek bir mekanizma sunabiliriz. Böylece, navigasyon isteklerinde aynı ipuçları sağlanabilir.

  3. ServiceWorker varsa neden müşteri ipuçlarına ihtiyacımız var? ServiceWorker'ın düzen, kaynak ve görüntü alanı genişlik bilgilerine erişimi yok. En azından, maliyetli döngüler yaratmadan 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) bunu yapabilirsiniz. İstemci ipuçları, bu verileri isteğin bir parçası olarak kullanılabilir hale getirmek için tarayıcıyla entegre olur.

  4. İstemci ipuçları yalnızca resim kaynakları için mi geçerli? DPR, Görünüm-Genişliği ve Genişlik ipuçlarının ardındaki temel kullanım alanı, resim öğeleri için kaynak seçimini etkinleştirmektir. Bununla birlikte, türden bağımsız olarak 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 istekleri neden Genişlik'i bildirmiyor? Site, resmin asıl boyutuna dayalı olduğu için tarayıcı istenen görüntü genişliğini bilmeyebilir. Sonuç olarak, bu tür istekler ve "görüntüleme genişliği" olmayan istekler (ör. bir JavaScript kaynağı) için Genişlik ipucu dikkate alınmaz. Genişlik ipuçları almak için resimlerinizde bir boyut değeri belirttiğinizden emin olun.

  6. <insert my Favori hint> nasıl? ServiceWorker, geliştiricilerin tüm giden isteklere müdahale edip bunları değiştirmesine (ör. yeni üstbilgiler ekleme) olanak tanır. Örneğin, mevcut bağlantı türünü belirtmek için NetInfo tabanlı bilgileri 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 edinebilirim, daha fazla demo görebilirim ve ne yapabilirim? Açıklama belgesine göz atın ve geri bildirim ya da başka sorularınız olursa GitHub'da sorunlarınızı açıklayabilirsiniz.